Всегда ли sizeof (некоторый указатель) равен четырем?

Например: sizeof(char*) возвращает 4. Как и int*, long long*, все, что я пробовал. Есть ли исключения из этого?


person Joel    schedule 29.12.2008    source источник
comment
Зачем отмечать это? Хороший вопрос для любого новичка.   -  person Martin York    schedule 30.12.2008
comment
Подозреваю, что в этом кроется еще один вопрос: что такое sizeof? или может быть Почему sizeof ‹любой указатель› == 4? Что такого особенного в 4 ?. Я прав?   -  person    schedule 31.12.2008
comment
Ну, это зависит от вашей платформы. Большинство реализаций имеют одинаковый размер для всех типов указателей на определенной платформе.   -  person phoeagon    schedule 16.05.2013
comment
Пожалуйста, спрашивайте либо C, либо C ++, а не оба в одном и том же вопросе. Это 2 разных языка. Включайте оба только тогда, когда вы спрашиваете о различиях или сходстве между ними.   -  person 12431234123412341234123    schedule 07.09.2020


Ответы (17)


Гарантия, которую вы получите, - это sizeof(char) == 1. Нет никаких других гарантий, в том числе гарантии, что sizeof(int *) == sizeof(double *).

На практике указатели будут иметь размер 2 в 16-битной системе (если вы можете его найти), 4 в 32-битной системе и 8 в 64-битной системе, но полагаться на данную размер.

person David Thornley    schedule 29.12.2008
comment
И 3 байта в 24-битной системе. Да, я работал над одним. Добро пожаловать в мир встраиваемых устройств. - person dwj; 30.12.2008
comment
Я также работал над 16-битными системами с 20-битными указателями. Я должен пойти посмотреть, какой размер возвращается в таком случае ... - person Judge Maygarden; 30.12.2008
comment
@monjardin: IIRC, 8086 был таким. Был 16-битный адрес и 4-битный сегментный регистр. Я считаю, что нормальный указатель NEAR был 16 бит, а указатель, объявленный как FAR, был больше, вероятно, 24, хотя я не уверен. - person rmeador; 30.12.2008
comment
Я работал над (32-битной) системой, в которой «char *» для чего-то имело другое битовое представление, чем «anthing_else *» в том же месте памяти. Вы научились гарантировать, что был объявлен 'malloc ()' (потому что в те давние времена malloc () возвращал 'char *', а не 'void *'). Остерегаться! - person Jonathan Leffler; 30.12.2008
comment
(продолжение): размер указателей был одинаковым во всех случаях; отличался просто битовый узор. Я не встречал систем, в которых указатели на разные типы данных имели разный размер. Я видел системы, в которых указатели кода (функции) отличаются по размеру от указателей данных. - person Jonathan Leffler; 30.12.2008
comment
В некоторых моделях памяти указатель на 8086 был 32-битным. 16-битный сегмент и 16-битное смещение. Процессор объединит их, сдвинув сегмент на 4 бита влево и добавив смещение, в результате чего получится 20-битный адрес. Два разных указателя могут указывать на один и тот же физический адрес! веселье! - person Ferruccio; 30.12.2008
comment
16-битные системы найти легко. Любой код, который работает в режиме THUMB на микросхеме ARM. - person ApplePieIsGood; 30.12.2008
comment
Извините, @ApplePieIsGood: код ARM THUMB по-прежнему 32-битный. Это просто метод сжатия размера инструкции с 32 до 16 бит, но адресное пространство остается прежним. - person Ben Combee; 30.12.2008
comment
другая гарантия заключается в том, что sizeof (char *) == sizeof (void *), потому что они должны иметь одинаковое представление (объект [размер] и значение [набор бит, соответствующих их значению] представление) - person Johannes Schaub - litb; 03.01.2009
comment
Ферруччо: Он не старый. Мой процессор Core 2 Quad также поддерживает реальный режим ;-P - person mmx; 09.01.2009
comment
Конечно, если у вас есть указатель на функцию-член класса, который использует множественное или виртуальное наследование, вы, скорее всего, получите совершенно другие размеры указателя. - person Eclipse; 14.01.2009
comment
itanium иногда использует 2 слова (2 указателя) для представления 1 указателя на функцию. - person osgx; 24.03.2010
comment
Есть и другие гарантии, например sizeof(int) <= sizeof(long). Они могут быть такими же или long могут быть значительно больше, чем int, но меньше никогда не будет. - person Jon Hanna; 10.08.2012
comment
@JudgeMaygarden звучит как 16-битный реальный мир - person Cole Johnson; 14.11.2012
comment
Поскольку вопрос требует исключений, следует отметить, что указатели нестатических функций-членов часто отличаются по размеру от обычных указателей, а также зависят от платформы, типа и т. Д. Кроме этого +1. - person John5342; 30.05.2013
comment
8 и 16 бит везде. Стиральные машины, холодильники, микросхемы, пульты дистанционного управления, ключи от машины. - person Kobor42; 17.07.2013
comment
Также существует гарантия, что все указатели на структуры имеют одинаковый размер и макет, а все указатели на объединения имеют одинаковый размер и представление. И указатели на подписанные / беззнаковые количества. И указатели на простые / константные / летучие объекты. - person gnasher729; 30.08.2015
comment
@ gnasher729: Я знаю, что есть гарантии относительно преобразования указателей, но где гарантия относительно размера и представления? - person ; 23.09.2015
comment
@ JohannesSchaub-litb: где в стандарте сказано, что sizeof(char*) == sizeof(void*)? - person Destructor; 04.04.2016
comment
Означает ли это, что независимо от типа данных, адрес есть адрес, и это то, что хранит указатель, по этой причине он должен быть одинакового размера? - person dud3; 04.04.2017
comment
@JudgeMaygarden Так что там написано? - person Sha Vuklia; 11.11.2018
comment
@ chux-ReinstateMonica: N1570 6.2.5 параграф 28 определяет, что в C указатель на void должен иметь те же требования к представлению и выравниванию, что и указатель на тип символа. Я думаю, это означало бы, что они одного размера. - person supercat; 24.03.2020
comment
@supercat Согласен. За последние 3 года я узнал об этой спецификации. Я подозреваю, что допустимые вариации размера указателя объекта среди int, FP, Struct, char - это особенность прошлого - сейчас я не знаю никаких вариаций. OTOH, указатели на функции и указатели на объекты различаются. - person chux - Reinstate Monica; 24.03.2020
comment
Как такое может быть sizeof int* != sizeof double*? Означает ли это, что int или double, находящиеся в куче, не могут иметь адреса большего размера? Например, если sizeof int* равно 4, а sizeof double* равно 8, то двойные числа могут иметь большие 8-байтовые адреса в куче, в то время как целые числа ограничиваются только 4-байтовыми адресами в куче? А как насчет пользовательских типов? Возможно ли также, что sizeof class1*! = sizeof class2*? - person Herrgott; 06.05.2021

Даже на простой 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 для размеров указателей на функцию-член.

Рэймонд Чен рассказал об этом здесь.

person Eclipse    schedule 13.01.2009
comment
Указатели на функции-члены - настоящая боль. К сожалению, не все компиляторы делают это так, как компилятор Digital Mars C ++, который во всех случаях возвращает 4. - person dalle; 18.02.2009
comment
gcc 4.72 распечатать все 8 ... Это не определено в стандарте c ++? - person Gob00st; 03.11.2012
comment
@ Gob00st: Единственное, что определено, это то, что char равно 1. Другие типы могут иметь любой размер, соответствующий этому компилятору. Нет требований к согласованности между этими типами указателей. - person Eclipse; 04.11.2012
comment
хорошо спасибо. Тогда неудивительно, что у gcc и VC разные реализации. - person Gob00st; 04.11.2012
comment
@Eclipse да, есть: char ‹= short‹ = int ‹= long‹ = long long - person Cole Johnson; 14.11.2012
comment
@ColeJohnson, откуда эта связь? Должно быть первым ‹= быть‹, а именно charshort? - person user3207158; 11.11.2019
comment
@ user3207158 Это отношение взято из стандарта. Он ничего не говорит об их битовой ширине, но гарантирует, что все размеры больше или равны предыдущим. char всегда меньше или равно short, ..., int всегда меньше или равно long и т. Д. У меня нет стандарта под рукой, поэтому я не могу назвать эталонный банкомат. - person Cole Johnson; 12.11.2019

Еще одно исключение из уже опубликованного списка. На 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-битных значений сегмента.

person dmityugov    schedule 30.12.2008
comment
Не сегмент, а скорее селектор - это не часть адреса памяти, а запись индекса в LDT или GDT и имеет некоторые флаги доступа. - person Roee Shenberg; 29.05.2012
comment
Почему в x86 есть сегменты и смещения, а адресное пространство плоское? - person phuclv; 05.03.2014
comment
@ LưuVĩnhPhúc Потому что он экономит место для очень распространенного случая ближних указателей, которые можно закодировать короче. - person Christopher Creutzig; 08.03.2014
comment
@ChristopherCreutzig, что означает, что сегменты используются для расширения адресного пространства, например, PAE? - person phuclv; 08.03.2014
comment
@ LưuVĩnhPhúc Я уже давно занимаюсь сборкой 32-битных систем. Я, кажется, помню, что вы можете сэкономить место для указателей, указывающих рядом с вашим кодом. Кроме того, не все 32-битные архитектуры - конечно, не все основанные на x86 - используют плоскую модель памяти. См., Например, tenouk.com/Bufferoverflowc/Bufferoverflow1a.html для более подробного обсуждения это, хотя, как я уже сказал, это было давно, и я не могу ни за что поручиться. - person Christopher Creutzig; 10.03.2014
comment
@ Lưu Vĩnh Phúc Сегментированная архитектура, представленная в 8088 и 8086, была основана на предположении, что цены на память были высокими, поэтому расходы можно было сэкономить, сохранив все в сегментах по 64 КБ. Это было большой головной болью для тех из нас, кто программировал низкоуровневый код в этой среде. Сейчас он редко используется, но все еще присутствует в процессорах Intel для мазохистов среди нас. - person pojo-guy; 04.07.2017

если вы компилируете для 64-битной машины, то это может быть 8.

person FryGuy    schedule 29.12.2008
comment
Хотя это обычно так, это не всегда так. Например, если вы компилируете на 64-битной машине, где размер слова составляет 64 бита, тогда sizeof (char *), вероятно, будет 1. Не говоря уже о более экзотических типах указателей даже на обычных машинах, таких как Eclipse и дмитюгов пишите. - person Kaz Dragon; 31.05.2013
comment
@KazDragon, sizeof(char*)==1? Уверены ли вы? Вы не имеете в виду size(char)==1? - person Aaron McDaid; 02.11.2013
comment
@AaronMcDaid Я действительно имел в виду sizeof (char *). sizeof (char) всегда равен 1. Но если ваше машинное слово 64-битное, а ваша среда разработки реализована таким образом, что CHAR_BITS = 64, тогда возможно, что указатель уместится в том же пространстве, что и char, и, следовательно, будет также быть 1. - person Kaz Dragon; 04.11.2013
comment
это неверно в x32-abi sites.google.com/site/x32abi - person phuclv; 05.03.2014
comment
Просто любопытно, @KazDragon вы можете привести пример машины, на которой CHAR_BITS = 64? - person rsaxvc; 12.04.2016
comment
@rsaxvc Нет, но я мог бы построить такой, если бы захотел. - person Kaz Dragon; 14.04.2016
comment
@KazDragon Я создаю (очень медленно, если не откладывать на потом) машину с 16-битными словами и без байтовой адресации. Хотя он все равно не может запустить C. - person user253751; 13.12.2019
comment
@ user253751: Конечно, есть ряд готовых микросхем DSP, подобных этому. - person Ben Voigt; 14.02.2020

Технически говоря, стандарт C гарантирует только то, что sizeof (char) == 1, а остальное зависит от реализации. Но на современных архитектурах x86 (например, чипах Intel / AMD) это довольно предсказуемо.

Вы, наверное, слышали, что процессоры описываются как 16-битные, 32-битные, 64-битные и т. Д. Это обычно означает, что процессор использует N-биты для целых чисел. Поскольку указатели хранят адреса памяти, а адреса памяти являются целыми числами, это фактически говорит вам, сколько битов будет использоваться для указателей. sizeof обычно измеряется в байтах, поэтому код, скомпилированный для 32-битных процессоров, сообщит, что размер указателей будет равен 4 (32 бит / 8 бит на байт), а код для 64-битных процессоров сообщит, что размер указателей равен 8 (64 бит / 8 бит на байт). Отсюда и ограничение в 4 ГБ ОЗУ для 32-битных процессоров - если каждый адрес памяти соответствует байту, для адресации большего объема памяти вам нужны целые числа больше 32 бит.

person Joseph Garvin    schedule 31.12.2008
comment
Вы, наверное, слышали, что процессоры описываются как 16-битные, 32-битные, 64-битные и т. Д. Это обычно означает, что процессор использует N-биты для целых чисел. - ›У меня 64-битная машина, но sizeof (int) составляет 4 байта. Если ваше утверждение верно, как это могло быть возможно ?! - person Sangeeth Saravanaraj; 17.04.2012
comment
@SangeethSaravanaraj: для обратной совместимости с 32-битным кодом они решили, что int по-прежнему будет 4 байта, и требуют, чтобы вы согласились на использование 8-байтового типа, указав 'long'. long на самом деле является родным размером слова на x86-64. Один из способов увидеть это, как правило, заключается в том, что компиляторы дополняют ваши структуры, чтобы выровнять их по словам (хотя могут быть архитектуры, в которых размер слова и выравнивание не связаны), поэтому, если вы создадите структуру с int (32 бита) в ней, и вызовите для него sizeof (), если вы вернетесь 8, вы знаете, что он дополняет их до 64-битного размера слова. - person Joseph Garvin; 18.04.2012
comment
@SangeethSaravanaraj: обратите внимание, что теоретически собственный размер слова процессора и то, что компилятор решает как int, может быть произвольно различным, просто до появления x86-64 было условием, что int - это собственный размер слова, где это долго, чтобы облегчить обратную совместимость. - person Joseph Garvin; 18.04.2012
comment
Спасибо за объяснение! :) - person Sangeeth Saravanaraj; 18.04.2012

Размер указателя в основном зависит от архитектуры системы, в которой он реализован. Например, размер указателя в 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-битной машине.

person Rndp13    schedule 05.06.2015

В дополнение к различиям в 16/32/64 бит могут происходить даже более странные вещи.

Были машины, на которых sizeof (int *) будет иметь одно значение, вероятно, 4, но где sizeof (char *) больше. Машины, которые естественным образом обращаются к словам, а не к байтам, должны «увеличивать» указатели на символы, чтобы указать, какую часть слова вы действительно хотите, чтобы правильно реализовать стандарт C / C ++.

Сейчас это очень необычно, поскольку разработчики оборудования узнали значение байтовой адресации.

person Darron    schedule 29.12.2008
comment
Компилятор C для векторных машин Cray, таких как T90, делает нечто подобное. Аппаратные адреса составляют 8 байтов и указывают на 8-байтовые слова. void* и char* обрабатываются программно и дополняются 3-битным смещением внутри слова, но поскольку на самом деле нет 64-битного адресного пространства, смещение сохраняется в 3-х старших битах 64 -битное слово. Таким образом, char* и int* имеют одинаковый размер, но имеют разные внутренние представления - и код, предполагающий, что указатели на самом деле являются просто целыми числами, может сильно потерпеть неудачу. - person Keith Thompson; 01.07.2012

8-битные и 16-битные указатели используются в большинстве низкопрофильных микроконтроллеров. Это означает каждую стиральную машину, микро, холодильник, старые телевизоры и даже автомобили.

Можно сказать, что это не имеет ничего общего с программированием в реальном мире. Но вот один из реальных примеров: Arduino с оперативной памятью 1-2-4k (в зависимости от чипа) с 2-х байтовыми указателями.

Он недавний, дешевый, доступный для всех и заслуживающий программирования.

person Kobor42    schedule 16.07.2013

В дополнение к тому, что люди говорят о 64-битных (или любых других) системах, существуют другие виды указателей, кроме указателей на объект.

Указатель на член может иметь почти любой размер, в зависимости от того, как они реализованы вашим компилятором: они даже не обязательно должны быть одинакового размера. Попробуйте использовать указатель на член класса POD, а затем указатель на член, унаследованный от одного из базовых классов класса с несколькими базами. Как весело.

person Steve Jessop    schedule 31.12.2008

Насколько я помню, он основан на размере адреса памяти. Таким образом, в системе с 32-битной схемой адреса sizeof вернет 4, поскольку это 4 байта.

person Will Mc    schedule 29.12.2008
comment
Такого требования нет. Нет даже требования, чтобы sizeof (unsigned int) == sizeof (signed int). Размер указателя на int всегда по определению будет sizeof (int *), на char sizeof (char *) и т. Д. Полагаться на любые другие предположения - плохая идея для переносимости. - person Mihai Limbășan; 30.12.2008
comment
Ах, теперь я понял. Спасибо за информацию. - person Will Mc; 30.12.2008
comment
По-прежнему может возвращать 2, если CHAR_BIT равен 16. sizeof () подсчитывает количество символов, а не октеты. - person MSalters; 06.04.2009
comment
@Mihai: В C ++ sizeof (unsigned int) == sizeof (signed int) это требование содержится в 3.9.1 / 3. Для каждого из стандартных целочисленных типов со знаком существует соответствующий (но другой) стандартный целочисленный тип без знака: unsigned char, unsigned short int, unsigned int, unsigned long int и unsigned long long int, каждый из которых занимает одинаковый объем памяти и имеет одинаковое выравнивание. требования как соответствующий целочисленный тип со знаком - person Ben Voigt; 31.08.2013

В общем, sizeof (почти все) изменится при компиляции на разных платформах. На 32-битной платформе указатели всегда имеют одинаковый размер. На других платформах (очевидным примером является 64-битная версия) это может измениться.

person Sean Reilly    schedule 29.12.2008

Нет, размер указателя может варьироваться в зависимости от архитектуры. Есть множество исключений.

person Judge Maygarden    schedule 29.12.2008

Размер указателя и int составляет 2 байта в компиляторе Turbo C на 32-битной машине Windows.

Таким образом, размер указателя зависит от компилятора. Но обычно большинство компиляторов реализовано для поддержки 4-байтовой переменной-указателя в 32-битной и 8-байтовой переменной-указателя на 64-битной машине).

Таким образом, размер указателя не одинаков на всех машинах.

person finalsemester.co.in    schedule 14.07.2014

В 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.

person Jayhello    schedule 08.06.2018

Причина, по которой размер вашего указателя составляет 4 байта, заключается в том, что вы компилируете для 32-битной архитектуры. Как указал FryGuy, на 64-битной архитектуре вы увидите 8.

person Will Bickford    schedule 29.12.2008

Указатель - это просто контейнер для адреса. На 32-битной машине ваш диапазон адресов составляет 32 бита, поэтому указатель всегда будет 4 байта. На 64-битной машине с диапазоном адресов 64 бита указатель будет иметь размер 8 байт.

person Ed S.    schedule 29.12.2008
comment
На 32-битной машине с 32-битными байтами sizeof (char *) может быть 1. - person Robert Gamble; 30.12.2008
comment
... с 32-битными байтами. Я не знал, что такие вещи существуют ... представьте себе. - person Ed S.; 30.12.2008
comment
На 32-битной утке sizeof (char *) возвращает PI - person Adriano Varoli Piazza; 30.12.2008

Просто для полноты и исторического интереса в мире 64-битных платформ существовали различные соглашения о размерах длинных и длинных длинных типов, называемых LLP64 и LP64, в основном между системами типа Unix и Windows. Старый стандарт под названием ILP64 также сделал int = 64-битным.

Microsoft сохранила LLP64, где longlong = 64-битная ширина, но долгое время оставалась равной 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

Источник: https://stackoverflow.com/a/384672/48026

person Hernán    schedule 20.08.2016