Rozne wielkosci wskaznikow w c++ , przypisywanie roznych typow wskaznikow do void*

0

witam
jakis czas temu widzialem na forum temat chyba zwiazany z wskaznikami .. chodzilo oto ze moga posiadac rozna wielkosc(lub jak kto woli zajmowac rozna wielkosc w pamieci) prawdopodobnie @Azarien to pokazywal
teraz do rzeczy przepisuje/kowertuje kod z c# do c++ dokladnie jest to silnik skryptow
jest tam pewna klasa (to uproszczona klasa oczywiscie zeby pokazac oco chdozi)
c#

	public class ScriptVariable
	{
        public object Value;
        public string Name;
        public Var_Types Type;
        public Var_State State;

		public ScriptVariable()
		{
			Value = (int)0;
			Name = "NULL";
			Type = Var_Types.INT;// enum
            		State = Var_State.PUBLIC;//enum
		}
	}

w kodzie nieraz przypisywane sa rozne typy do Value
np

...
                case Var_Types.NULL:
                    sout.Value = null;
                    break;
                case Var_Types.INT:
                    sout.Value = (long)Value;
                    break;
                case Var_Types.DOUBLE:
                    sout.Value = (double)Value;
                    break;
...

w c++
uzylem void* jako zamiennik klasy object, niby git ale zastanawialem sie nad tymi wielkosciami wskaznikow czy czasem sie niewkopie w jakies bledy
niestety na razie niemoge przetestowac dzialania bo wciaz to konwertuje...

no to te pytanie czy jest to bezpieczne ? do void* beda przypisywane typy takie jak *double , *int(64bitowy) , *string , i 1 specialna klasa odzwierciedlajaca klasy zdefiniowane w skrypcie przez uzytkownika

jezeli bedzie to bezpieczne to 2 pytanie
czy bedzie normalnie dzialac unique_ptr z typem void* ?

0

W C# wszystko pochodzi od object, w C++ - nie.
Wiec dla tego celu powinieneś zrobić klasę ValueAny oraz pochodzące od niej ValueDouble, ValueInt, ValueBool, ValueString itp.

1

Dowolny wskaźnik do danych (w sensie zmiennych) można bezpiecznie rzutować do void*. Nie wolno tego robić jedynie w przypadku wskaźników na funkcje i metody, bo po pierwsze: mogą mieć różne wielkości (jak pokazał Azarien) a po drugie: nie wszystkie architektury są von Neumanna i przestrzeń kodu i danych mogą być osobne (np. architektura Harvard).

Podsumowując – jest to bezpieczne. unique_ptr<void> też będzie działał prawidłowo.

0

Hey, a mógłby ktoś podać linka do tego wątku, w którym jest mowa o wielkościach wskaźników?
Sam jestem trochę ciekaw jak to jest, że wskaźnik do obiektu jakiejś klasy, która zawiera m.in. zmienne typu double zajmuje 4 bajty a do zmiennej typu double 8...
Z góry dzięki

0

Nie, to nie tak. Każdy wskaźnik do zmiennej typu char, int, double etc., do instancji struktury, klasy bądź unii oraz do enum można bezpiecznie rzutować do void* i z powrotem mając gwarancję, że wartość pointera się nie zmieni. Różnica w wielkości może występować przy wskaźnikach na funkcje i metody klas (czyli wskaźniki do „kodu”, a nie „danych”).

Posta nie udało mi się znaleźć, niech się wypowie @Azarien, może pamięta gdzie o tym pisał. :)

0

dzieki za odpowiedzi
tamten temat byl na tyle ciekawy poniewaz zwrucono uwage ze kompilator vc++ i g++ potrafia uzywac innych wielkosci wskaznikow w takim samym kodzie
niestety niezapisalem linku do niego

0
class Bazowa1 {};
class Bazowa2 {};
class Pochodna1 : Bazowa1 {};
class Pochodna2 : Bazowa2 {};
class Pochodna3 : Bazowa1, Bazowa2 {};

#include <iostream>
using namespace std;

int main()
{
	void (Bazowa1::*ptr1)();
	void (Bazowa2::*ptr2)();
	void (Pochodna1::*ptr3)();
	void (Pochodna2::*ptr4)();
	void (Pochodna3::*ptr5)();
	
	                              // Visual     GCC
	cout << sizeof(void*) << endl;// 4          4
	cout << sizeof(ptr1) << endl; // 4          8
	cout << sizeof(ptr2) << endl; // 4          8
	cout << sizeof(ptr3) << endl; // 4          8
	cout << sizeof(ptr4) << endl; // 4          8
	cout << sizeof(ptr5) << endl; // 8. huh!?   8

	return 0;
}

wyniki dla 32 bitów, żeby ktoś nie mówił że to kwestia architektury…

wnioski:

  1. nie można rzutować wskaźnika na metodę na void*, bo nie musi mieć tego samego rozmiaru
  2. nie można rzutowac wskaźnika na metodę klasy A na wskaźnik metody klasy B, bo mogą być różnych rozmiarów (patrz ptr5 w Visualu)
0

Ciekawszy przykład, ze zwykłymi wskaźnikami (bez wskaźników na metody), za to z „egzotyczną” (na dzisiejsze czasy) architekturą:

#include <iostream>
using namespace std;

int main()
{
    int* p1;       // wskaźnik na dane
    void (*p2)();  // wskaźnik na kod
    
    cout << sizeof(void*) << endl;
    cout << sizeof(p1) << endl;
    cout << sizeof(p2) << endl;
}

32-bitowy Windows:

4
4
4

64-bitowy Windows:

8
8
8

A teraz najciekawsze.
16-bitowy MS-DOS, kompilator Open Watcom. Do wyboru mamy różne "modele pamięci":

small:

2
2
2

compact:

4
4
2

medium:

2
2
4

large:

4
4
4

32-bitowy DOS:

4
4
4

wniosek: wskaźnik na dane może mieć inny rozmiar niż wskaźnik na kod. void* ma zawsze rozmiar wskaźnika na dane.

1 użytkowników online, w tym zalogowanych: 0, gości: 1