Всегда ли sizeof(некоторый указатель) равен четырем?
Например:sizeof(char*)
возвращает 4. Как и int*
, long long*
, все, что я пробовал. Есть ли исключения из этого?
17 ответов
Вы получаете гарантию, что sizeof(char) == 1
, Других гарантий нет, в том числе нет sizeof(int *) == sizeof(double *)
,
На практике указатели будут иметь размер 2 в 16-битной системе (если вы можете его найти), 4 в 32-битной системе и 8 в 64-битной системе, но полагаться на конкретную информацию нечего размер.
Даже на простой 32-разрядной платформе x86 вы можете получить указатели разных размеров, попробуйте это на примере:
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;
}
В Visual C++ 2008 я получаю 4, 12 и 8 для размеров функции указателя на член.
Раймонд Чен говорил об этом здесь.
Просто еще одно исключение из уже опубликованного списка. На 32-битных платформах указатели могут занимать 6, а не 4 байта:
#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;
}
Если вы скомпилируете эту программу с помощью Open Watcom и запустите ее, вы получите 6, потому что поддерживаемые ею дальние указатели состоят из 32-битных смещений и 16-битных значений сегментов.
Если вы компилируете для 64-битной машины, то это может быть 8.
Технически говоря, стандарт C гарантирует только то, что sizeof(char) == 1, а остальное зависит от реализации. Но на современных архитектурах x86 (например, на чипах Intel/AMD) это вполне предсказуемо.
Вы, вероятно, слышали, что процессоры описываются как 16-битные, 32-битные, 64-битные и т. Д. Обычно это означает, что процессор использует N-бит для целых чисел. Поскольку указатели хранят адреса памяти, а адреса памяти являются целыми числами, это фактически говорит вам, сколько битов будет использоваться для указателей. sizeof обычно измеряется в байтах, поэтому код, скомпилированный для 32-разрядных процессоров, сообщит, что размер указателей равен 4 (32 бита / 8 бит на байт), а код для 64-разрядных процессоров сообщит, что размер указателей равен 8 (64 бита / 8 бит на байт). Отсюда и ограничение в 4 ГБ ОЗУ для 32-разрядных процессоров - если каждый адрес памяти соответствует байту, для адресации большего объема памяти нужны целые числа больше 32-разрядных.
Размер указателя в основном зависит от архитектуры системы, в которой он реализован. Например, размер указателя в 32-разрядных системах составляет 4 байта (32-разрядных) и 8 байтов (64-разрядных) в 64-разрядных компьютерах. Типы битов в машине - это не что иное, как адрес памяти, который он может иметь. 32-битные машины могут иметь 2^32
адресное пространство и 64-битные машины могут иметь до 2^64
адресные пространства. Таким образом, указатель (переменная, которая указывает на ячейку памяти) должен иметь возможность указывать на любой адрес памяти (2^32 for 32 bit and 2^64 for 64 bit
) что машина держит.
По этой причине мы видим размер указателя равным 4 байта на 32-битной машине и 8 байтов на 64-битной машине.
8-битные и 16-битные указатели используются в большинстве низкопрофильных микроконтроллеров. Это означает, что каждая стиральная машина, микро, холодильник, старые телевизоры и даже автомобили.
Можно сказать, что это не имеет ничего общего с программированием в реальном мире. Но вот один пример из реальной жизни: Arduino с оперативной памятью 1-2-4 КБ (в зависимости от чипа) с 2-байтовыми указателями.
Это недавно, дешево, доступно для всех и стоит кодирования.
В дополнение к разнице в 16/32/64 битов могут происходить и более странные вещи.
Были машины, где sizeof(int *) будет иметь одно значение, вероятно, 4, но где sizeof(char *) больше. Машины, которые естественным образом адресуют слова вместо байтов, должны "дополнять" символьные указатели, чтобы указать, какая часть слова вам действительно нужна, чтобы должным образом реализовать стандарт C/C++.
Это теперь очень необычно, так как разработчики аппаратного обеспечения узнали значение адресации байтов.
В дополнение к тому, что люди говорили о 64-битных (или любых других) системах, существуют и другие виды указателей, кроме указателя на объект.
Указатель на член может быть практически любого размера, в зависимости от того, как он реализован вашим компилятором: они не обязательно даже одного размера. Попробуйте указатель на член класса POD, а затем указатель на член, унаследованный от одного из базовых классов класса с несколькими основаниями. Как весело.
Насколько я помню, это основано на размере адреса памяти. Таким образом, в системе с 32-битной адресной схемой size of вернет 4, поскольку это 4 байта.
Размер указателя и int составляет 2 байта в компиляторе Turbo C на Windows 32-битной машине.
Таким образом, размер указателя зависит от компилятора. Но, как правило, большинство компиляторов реализовано для поддержки 4-байтовой переменной указателя в 32-битной и 8-байтовой переменной указателя в 64-битной машине).
Таким образом, размер указателя не одинаков на всех машинах.
В общем случае sizeof(почти все) будет меняться при компиляции на разных платформах. На 32-битной платформе указатели всегда имеют одинаковый размер. На других платформах (64-битный является очевидным примером) это может измениться.
Нет, размер указателя может варьироваться в зависимости от архитектуры. Есть множество исключений.
В Win64 (Cygwin GCC 5.4), давайте посмотрим на приведенный ниже пример:
Сначала протестируйте следующую структуру:
struct list_node{
int a;
list_node* prev;
list_node* next;
};
struct test_struc{
char a, b;
};
Тестовый код ниже:
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;
Выход ниже:
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
Вы можете увидеть это в 64-битном, sizeof(pointer)
является 8
,
Причина, по которой размер вашего указателя составляет 4 байта, заключается в том, что вы компилируете для 32-битной архитектуры. Как отметил FryGuy, на 64-битной архитектуре вы увидите 8.
Указатель - это просто контейнер для адреса. На 32-битной машине ваш диапазон адресов составляет 32 бита, поэтому указатель всегда будет 4 байта. На 64-битной машине, где у вас диапазон адресов 64 бита, указатель будет 8 байтов.
Просто для полноты и исторического интереса, в 64-битном мире существовали различные соглашения о платформе для размеров длинных и длинных длинных типов, называемых LLP64 и LP64, в основном между системами Unix-типа и Windows. Старый стандарт с именем ILP64 также имеет ширину int = 64-bit.
Microsoft поддерживала LLP64, где longlong = 64-битная ширина, но long остался на 32, для облегчения портирования.
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
Источник: /questions/37376420/kakov-razmer-long-v-64-bitnoj-windows/37376453#37376453