Na przykład:
sizeof(char*)
zwraca 4. Jak nie int*
, long long*
wszystko, co próbowałem. Czy są jakieś wyjątki od tego?
Na przykład:
sizeof(char*)
zwraca 4. Jak nie int*
, long long*
wszystko, co próbowałem. Czy są jakieś wyjątki od tego?
Odpowiedzi:
To gwarancja, którą otrzymujesz sizeof(char) == 1
. Nie ma innych gwarancji, w tym żadnej gwarancji tego sizeof(int *) == sizeof(double *)
.
W praktyce wskaźniki będą miały rozmiar 2 w systemie 16-bitowym (jeśli można go znaleźć), 4 w systemie 32-bitowym i 8 w systemie 64-bitowym, ale nic nie można zyskać polegając na danym rozmiar.
Nawet na zwykłej 32-bitowej platformie x86 możesz uzyskać różne rozmiary wskaźników, wypróbuj to na przykład:
struct A {};
struct B : virtual public A {};
struct C {};
struct D : public A, public C {};
int main()
{
cout << "A:" << sizeof(void (A::*)()) << endl;
cout << "B:" << sizeof(void (B::*)()) << endl;
cout << "D:" << sizeof(void (D::*)()) << endl;
}
W Visual C ++ 2008 dostaję 4, 12 i 8 dla rozmiarów funkcji wskaźniki do członka.
Raymond Chen mówił o tym tutaj .
Kolejny wyjątek od już opublikowanej listy. Na platformach 32-bitowych wskaźniki mogą zająć 6, a nie 4 bajty:
#include <stdio.h>
#include <stdlib.h>
int main() {
char far* ptr; // note that this is a far pointer
printf( "%d\n", sizeof( ptr));
return EXIT_SUCCESS;
}
Jeśli skompilujesz ten program z Open Watcom i uruchomisz go, otrzymasz 6, ponieważ dalekie obsługiwane wskaźniki składają się z 32-bitowego przesunięcia i 16-bitowych wartości segmentów
jeśli kompilujesz dla komputera 64-bitowego, może to być 8.
sizeof(char*)==1
? Jesteś pewny? Nie masz na myśli size(char)==1
?
Technicznie rzecz biorąc, standard C gwarantuje tylko, że sizeof (char) == 1, a reszta zależy od implementacji. Ale na nowoczesnych architekturach x86 (np. Układach Intel / AMD) jest to dość przewidywalne.
Prawdopodobnie słyszałeś procesory opisane jako 16-bitowe, 32-bitowe, 64-bitowe itp. Zazwyczaj oznacza to, że procesor używa bitów N do liczb całkowitych. Ponieważ wskaźniki przechowują adresy pamięci, a adresy pamięci są liczbami całkowitymi, to skutecznie informuje, ile bitów zostanie wykorzystanych na wskaźniki. sizeof jest zwykle mierzony w bajtach, więc kod skompilowany dla procesorów 32-bitowych zgłasza rozmiar wskaźników na 4 (32 bity / 8 bitów na bajt), a kod dla 64-bitowych procesorów zgłasza rozmiar wskaźników na 8 (64 bity / 8 bitów na bajt). Stąd bierze się ograniczenie 4 GB pamięci RAM dla procesorów 32-bitowych - jeśli każdy adres pamięci odpowiada bajtowi, do adresowania większej ilości pamięci potrzebne są liczby całkowite większe niż 32-bitowe.
Rozmiar wskaźnika zasadniczo zależy od architektury systemu, w którym jest on implementowany. Na przykład rozmiar wskaźnika w 32 bitach wynosi 4 bajty (32 bity) i 8 bajtów (64 bity) na komputerach 64-bitowych. Typy bitów w maszynie to tylko adres pamięci, który może mieć. Maszyny 32-bitowe mogą mieć 2^32
przestrzeń adresową, a maszyny 64-bitowe mogą mieć 2^64
przestrzenie adresowe. Tak więc wskaźnik (zmienna wskazująca lokalizację pamięci) powinien być w stanie wskazać dowolny adres pamięci (2^32 for 32 bit and 2^64 for 64 bit
) przechowywany przez maszynę.
Z tego powodu widzimy, że rozmiar wskaźnika to 4 bajty w maszynie 32-bitowej i 8 bajtów w maszynie 64-bitowej.
Oprócz różnic 16/32/64 bitów mogą wystąpić nawet dziwniejsze rzeczy.
Istnieją maszyny, w których sizeof (int *) będzie miała jedną wartość, prawdopodobnie 4, ale w których sizeof (char *) jest większy. Maszyny, które naturalnie adresują słowa zamiast bajtów, muszą „uzupełnić” wskaźniki znaków, aby określić, jakiej części słowa naprawdę chcesz, aby poprawnie wdrożyć standard C / C ++.
Jest to obecnie bardzo niezwykłe, ponieważ projektanci sprzętu nauczyli się wartości adresowalności bajtów.
void*
i char*
są obsługiwane w oprogramowaniu i są powiększone o 3-bitowe przesunięcie w obrębie słowa - ale ponieważ tak naprawdę nie ma 64-bitowej przestrzeni adresowej, przesunięcie jest przechowywane w 3-bitowych rzędach 64-bitowych wyższego rzędu słowo. Tak char*
i int*
są tej samej wielkości, ale mają różne reprezentacje wewnętrzne - i kod, który zakłada, że wskaźniki są „naprawdę” tylko całkowitymi może nie źle.
Wskaźniki 8-bitowe i 16-bitowe są używane w większości mikrokontrolerów niskoprofilowych. Oznacza to, że każda pralka, kuchenka mikrofalowa, lodówka, starsze telewizory, a nawet samochody.
Można powiedzieć, że nie mają one nic wspólnego z programowaniem w świecie rzeczywistym. Ale oto jeden przykład z prawdziwego świata: Arduino z ram 1-2-2k (w zależności od układu) z 2 bajtowymi wskaźnikami.
Jest to najnowsze, tanie, dostępne dla wszystkich i warte kodowania.
Oprócz tego, co ludzie mówili o systemach 64-bitowych (lub cokolwiek innego), istnieją inne rodzaje wskaźników niż wskaźnik do obiektu.
Wskaźnik do elementu może mieć prawie dowolny rozmiar, w zależności od sposobu implementacji przez kompilator: niekoniecznie mają one jednakowy rozmiar. Wypróbuj wskaźnik do elementu klasy POD, a następnie wskaźnik do elementu dziedziczony z jednej z klas podstawowych klasy z wieloma bazami. Co za zabawa.
Z tego co pamiętam, opiera się na wielkości adresu pamięci. Tak więc w systemie z 32-bitowym schematem adresu sizeof zwróci 4, ponieważ to 4 bajty.
sizeof (unsigned int) == sizeof (signed int)
ten wymóg znajduje się w 3.9.1 / 3. „Dla każdego standardu ze znakiem typów istnieje odpowiadający (ale inne) stosuje się standardowe unsigned całkowitą: unsigned char
, unsigned short int
, unsigned int
, unsigned long int
i unsigned long long int
, z których każdy zajmuje tę samą ilość miejsca i ma takie same wymagania wyrównania, co odpowiadający ze znakiem Typ „
Ogólnie rzecz biorąc, sizeof (właściwie wszystko) zmieni się podczas kompilacji na różnych platformach. Na platformie 32-bitowej wskaźniki są zawsze tego samego rozmiaru. Na innych platformach (64-bitowy oczywisty przykład) może się to zmienić.
Nie, rozmiar wskaźnika może się różnić w zależności od architektury. Istnieje wiele wyjątków.
Rozmiar wskaźnika i liczby int wynosi 2 bajty w kompilatorze Turbo C na 32-bitowym komputerze z systemem Windows.
Zatem rozmiar wskaźnika zależy od kompilatora. Ale generalnie większość kompilatorów jest implementowana do obsługi 4-bajtowej zmiennej wskaźnika w 32-bitowej i 8-bajtowej zmiennej wskaźnika w 64-bitowej maszynie).
Dlatego rozmiar wskaźnika nie jest taki sam na wszystkich komputerach.
Rozmiar wskaźnika wynosi 4 bajty, ponieważ kompilujesz się w architekturze 32-bitowej. Jak wskazał FryGuy, w architekturze 64-bitowej zobaczyłbyś 8.
W Win64 (Cygwin GCC 5.4) zobaczmy następujący przykład:
Najpierw przetestuj następującą strukturę:
struct list_node{
int a;
list_node* prev;
list_node* next;
};
struct test_struc{
char a, b;
};
Kod testowy znajduje się poniżej:
std::cout<<"sizeof(int): "<<sizeof(int)<<std::endl;
std::cout<<"sizeof(int*): "<<sizeof(int*)<<std::endl;
std::cout<<std::endl;
std::cout<<"sizeof(double): "<<sizeof(double)<<std::endl;
std::cout<<"sizeof(double*): "<<sizeof(double*)<<std::endl;
std::cout<<std::endl;
std::cout<<"sizeof(list_node): "<<sizeof(list_node)<<std::endl;
std::cout<<"sizeof(list_node*): "<<sizeof(list_node*)<<std::endl;
std::cout<<std::endl;
std::cout<<"sizeof(test_struc): "<<sizeof(test_struc)<<std::endl;
std::cout<<"sizeof(test_struc*): "<<sizeof(test_struc*)<<std::endl;
Dane wyjściowe są poniżej:
sizeof(int): 4
sizeof(int*): 8
sizeof(double): 8
sizeof(double*): 8
sizeof(list_node): 24
sizeof(list_node*): 8
sizeof(test_struc): 2
sizeof(test_struc*): 8
Widać, że w 64-bitowym, sizeof(pointer)
jest 8
.
Wskaźnik jest tylko kontenerem na adres. Na maszynie 32-bitowej zakres adresów wynosi 32 bity, więc wskaźnik zawsze będzie wynosił 4 bajty. Na komputerze 64-bitowym, jeśli masz zakres adresów 64 bitów, wskaźnik będzie wynosił 8 bajtów.
Dla kompletności i historycznego zainteresowania w świecie 64-bitowym istniały różne konwencje platform dotyczące rozmiarów długich i długich typów, nazwanych LLP64 i LP64, głównie między systemami typu Unix a Windows. Stary standard o nazwie ILP64 również miał szerokość int = 64-bit.
Microsoft utrzymywał LLP64, gdzie longlong = 64 bit szerokości, ale długo pozostawał na 32, dla łatwiejszego przenoszenia.
Type ILP64 LP64 LLP64
char 8 8 8
short 16 16 16
int 64 32 32
long 64 64 32
long long 64 64 64
pointer 64 64 64