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

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

Зачем отмечать это? Хороший вопрос для любого новичка.

Martin York 30.12.2008 02:11

Подозреваю, что в этом кроется еще один вопрос: "Что такое sizeof?" или может быть «Почему sizeof <any pointer> == 4? Что такого особенного в 4?». Я прав?

user3458 31.12.2008 20:14

Ну, это зависит от вашей платформы. Большинство реализаций имеют одинаковый размер для всех типов указателей на определенной платформе.

phoeagon 16.05.2013 16:13

Пожалуйста, спрашивайте C или C++, а не оба в одном и том же вопросе. Это 2 разных языка. Включайте и то и другое только тогда, когда вы спрашиваете о различиях или сходстве между ними.

12431234123412341234123 07.09.2020 14:17
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
234
4
123 649
17
Перейти к ответу Данный вопрос помечен как решенный

Ответы 17

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

Хотя это обычно так, это не всегда так. Например, если вы компилируете на 64-битной машине, где размер слова составляет 64 бита, то sizeof (char *), вероятно, будет 1. Не говоря уже о более экзотических типах указателей даже на обычных машинах, таких как Eclipse и дмитюгов пишите.

Kaz Dragon 31.05.2013 12:01

@KazDragon, sizeof(char*)==1? Уверены ли вы? Вы не имеете в виду size(char)==1?

Aaron McDaid 02.11.2013 14:34

@AaronMcDaid Я действительно имел в виду sizeof (char *). sizeof (char) всегда равен 1. Но если ваше машинное слово 64-битное, а ваша среда разработки реализована таким образом, что CHAR_BITS = 64, то возможно, что указатель уместится в том же пространстве, что и char, и, следовательно, будет также быть 1.

Kaz Dragon 04.11.2013 13:16

это не правда в x32-abisites.google.com/site/x32abi

phuclv 05.03.2014 13:20

Просто любопытно, @KazDragon вы можете привести пример машины, на которой CHAR_BITS = 64?

rsaxvc 12.04.2016 07:26

@rsaxvc Нет, но я мог бы построить такой, если бы захотел.

Kaz Dragon 14.04.2016 10:12

@KazDragon Я создаю (очень медленно, если не откладывать на потом) машину с 16-битными словами и без байтовой адресации. Хотя он все равно не может запустить C.

user253751 13.12.2019 19:01

@ user253751: Конечно, есть ряд готовых микросхем DSP, подобных этому.

Ben Voigt 14.02.2020 19:42

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

Такого требования нет. Нет даже требования, чтобы sizeof (unsigned int) == sizeof (signed int). Размер указателя на int всегда по определению будет sizeof (int *), на char sizeof (char *) и т. д. Полагаться на любые другие предположения - плохая идея для переносимости.

Mihai Limbășan 30.12.2008 14:15

Ах, теперь я понял. Спасибо за информацию.

Will Mc 30.12.2008 18:52

По-прежнему может возвращать 2, если CHAR_BIT равен 16. sizeof () подсчитывает количество символов, а не октеты.

MSalters 06.04.2009 17:56

@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, каждый из которых занимает такой же объем памяти и имеет те же требования к выравниванию, что и соответствующий целочисленный тип со знаком»

Ben Voigt 31.08.2013 06:49

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

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

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

На 32-битной машине с 32-битными байтами sizeof (char *) может быть 1.

Robert Gamble 30.12.2008 02:28

«... с 32-битными байтами». Я не знал, что такие вещи существуют ... представьте себе.

Ed S. 30.12.2008 09:48

На 32-битной утке sizeof (char *) возвращает PI

Adriano Varoli Piazza 30.12.2008 14:08
Ответ принят как подходящий

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

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

И 3 байта в 24-битной системе. Да, я работал над одним. Добро пожаловать в мир встраиваемых устройств.

dwj 30.12.2008 02:13

Я также работал над 16-битными системами с 20-битными указателями. Я должен пойти посмотреть, какой размер возвращается в таком случае ...

Judge Maygarden 30.12.2008 02:16

@monjardin: IIRC, 8086 был таким. Был 16-битный адрес и 4-битный сегментный регистр. Я считаю, что нормальный указатель «NEAR» был 16 бит, а указатель, объявленный как «FAR», был больше, вероятно, 24, хотя я не уверен.

rmeador 30.12.2008 02:22

Я работал над (32-битной) системой, в которой «char *» для чего-то имело другое битовое представление, чем «anthing_else *» в том же месте памяти. Вы научились гарантировать, что был объявлен malloc () (потому что в те давние времена malloc () возвращал char *, а не void *). Остерегаться!

Jonathan Leffler 30.12.2008 03:10

(продолжение): размер указателей был одинаковым во всех случаях; отличался просто битовый узор. Я не встречал систем, в которых указатели на разные типы данных имели разные размеры. Я видел системы, в которых указатели кода (функции) отличаются по размеру от указателей данных.

Jonathan Leffler 30.12.2008 03:14

В некоторых моделях памяти указатель на 8086 был 32-битным. 16-битный сегмент и 16-битное смещение. Процессор объединит их, сдвинув сегмент на 4 бита влево и добавив смещение, в результате чего получится 20-битный адрес. Два разных указателя могут указывать на один и тот же физический адрес! веселье!

Ferruccio 30.12.2008 06:27

16-битные системы легко найти. Любой код, который работает в режиме THUMB на микросхеме ARM.

ApplePieIsGood 30.12.2008 18:26

Извините, @ApplePieIsGood: код ARM THUMB по-прежнему 32-битный. Это просто метод сжатия размера инструкции с 32 до 16 бит, но адресное пространство остается прежним.

Ben Combee 30.12.2008 19:40

другой гарантией является то, что sizeof (char *) == sizeof (void *), потому что они должны иметь одинаковое представление (объект [размер] и значение [набор бит, соответствующих их значению] представление)

Johannes Schaub - litb 03.01.2009 19:03

Ферруччо: Он не старый. Мой процессор Core 2 Quad также поддерживает реальный режим ;-P

mmx 09.01.2009 16:59

Конечно, если у вас есть указатель на функцию-член класса, который использует множественное или виртуальное наследование, вы, скорее всего, получите совершенно другие размеры указателя.

Eclipse 14.01.2009 01:55

itanium иногда использует 2 слова (2 указателя) для представления 1 указателя на функцию.

osgx 24.03.2010 03:19

Есть и другие гарантии, например sizeof(int) <= sizeof(long). Они могут быть такими же, или long может быть значительно больше, чем int, но меньше никогда не будет.

Jon Hanna 10.08.2012 16:52

@JudgeMaygarden звучит как 16-битный реальный мир

Cole Johnson 14.11.2012 10:10

Поскольку вопрос требует исключений, следует отметить, что указатели нестатических функций-членов часто отличаются по размеру от обычных указателей, а также зависят от платформы, типа и т. д. Кроме этого +1.

John5342 30.05.2013 16:59

8 и 16 бит везде. Стиральные машины, холодильники, микроконтроллеры, дистанционные контроллеры, ключи от машины.

Kobor42 17.07.2013 00:34

Также существует гарантия, что все указатели на структуры имеют одинаковый размер и макет, а все указатели на объединения имеют одинаковый размер и представление. И указатели на подписанные / беззнаковые количества. И указатели на простые / константные / летучие объекты.

gnasher729 30.08.2015 16:34

@ gnasher729: Я знаю, что есть гарантии относительно указателей Кастинг, но где гарантия относительно размера и представления?

user1084944 23.09.2015 09:03

@ JohannesSchaub-litb: где в стандарте указано, что sizeof(char*) == sizeof(void*)?

Destructor 04.04.2016 18:29

Означает ли это, что, независимо от типа данных, адрес есть адрес, и это то, что хранит указатель, по этой причине он должен быть одинакового размера?

dud3 04.04.2017 00:00

@JudgeMaygarden Так что там написано?

Sha Vuklia 11.11.2018 04:29

@ chux-ReinstateMonica: N1570 6.2.5 параграф 28 определяет, что в C, «указатель на void должен иметь те же требования к представлению и выравниванию, что и указатель на тип символа». Я думаю, это будет означать, что они одного размера.

supercat 24.03.2020 01:07

@supercat Согласен. За последние 3 года я узнал об этой спецификации. Я подозреваю, что допустимые вариации размера указателя на объект среди int, FP, Struct, char - это особенность прошлого - сейчас я не знаю никаких вариаций. OTOH, указатели на функции и указатели на объекты различаются.

chux - Reinstate Monica 24.03.2020 01:39

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

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

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

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

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

Keith Thompson 01.07.2012 05:49

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

Не сегмент, а скорее селектор - это не часть адреса памяти, а запись индекса в LDT или GDT и имеет некоторые флаги доступа.

Roee Shenberg 29.05.2012 05:45

Почему в x86 есть сегменты и смещения, а адресное пространство плоское?

phuclv 05.03.2014 13:20

@ LưuVĩnhPhúc Потому что он экономит место для очень распространенного случая ближних указателей, которые можно закодировать короче.

Christopher Creutzig 08.03.2014 13:16

@ChristopherCreutzig, что означает, что сегменты используются для расширения адресного пространства, например, PAE?

phuclv 08.03.2014 14:06

@ LưuVĩnhPhúc Я уже давно занимаюсь сборкой чего-либо 32-битного. Я, кажется, помню, что вы можете сэкономить место для указателей, указывающих рядом с вашим кодом. Кроме того, не все 32-битные архитектуры - конечно, не все основанные на x86 - используют плоскую модель памяти. См., Например, tenouk.com/Bufferoverflowc/Bufferoverflow1a.html для более подробного обсуждения этого вопроса, хотя, как я уже сказал, прошло много времени, и я не могу ни за что поручиться.

Christopher Creutzig 10.03.2014 01:34

@ Lưu Vĩnh Phúc Сегментированная архитектура, представленная в 8088 и 8086, была основана на предположении, что цены на память были высокими, поэтому расходы можно было сэкономить, сохранив все в сегментах по 64 КБ. Это было большой головной болью для тех из нас, кто программировал низкоуровневый код в этой среде. Сейчас он редко используется, но все еще присутствует в процессорах Intel для мазохистов среди нас.

pojo-guy 04.07.2017 21:44

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

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

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

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

«Вы, наверное, слышали, что процессоры описываются как 16-битные, 32-битные, 64-битные и т. д. Это обычно означает, что процессор использует N бит для целых чисел». -> У меня 64-битная машина, но sizeof (int) составляет 4 байта. Если ваше утверждение верно, как это могло быть возможно ?!

Sangeeth Saravanaraj 17.04.2012 22:27

@SangeethSaravanaraj: для обратной совместимости с 32-битным кодом они решили, что int по-прежнему будет 4 байта, и требуют, чтобы вы согласились на использование 8-байтового типа, указав 'long'. long - собственно размер слова на x86-64. Один из способов убедиться в этом заключается в том, что обычно компиляторы дополняют ваши структуры, чтобы выровнять их по словам (хотя могут быть архитектуры, в которых размер слова и выравнивание не связаны), поэтому, если вы создаете структуру с int (32-битным) в ней, и вызовите для него sizeof (), если вы вернетесь 8, вы знаете, что он дополняет их до 64-битного размера слова.

Joseph Garvin 18.04.2012 00:08

@SangeethSaravanaraj: обратите внимание, что теоретически собственный размер слова ЦП и то, что компилятор решает как int, может быть произвольно различным, просто до появления x86-64 было условием, что int - это собственный размер слова, где это долго, чтобы облегчить обратную совместимость.

Joseph Garvin 18.04.2012 00:10

Спасибо за объяснение! :)

Sangeeth Saravanaraj 18.04.2012 00:11

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

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

Указатели на функции-члены - настоящая боль. К сожалению, не все компиляторы делают это так, как компилятор Digital Mars C++, который во всех случаях возвращает 4.

dalle 18.02.2009 18:21

gcc 4.72 распечатать все 8 ... Это не определено в стандарте C++?

Gob00st 03.11.2012 22:54

@ Gob00st: Единственное, что определено, это то, что char равно 1. Другие типы могут иметь любой размер, соответствующий этому компилятору. Нет требований к согласованности между этими типами указателей.

Eclipse 04.11.2012 02:38

хорошо спасибо. Тогда неудивительно, что у gcc и VC разные реализации.

Gob00st 04.11.2012 03:05

@Eclipse да, есть: char <= short <= int <= long <= long long

Cole Johnson 14.11.2012 10:10

@ColeJohnson, откуда эта связь? Должен ли первый <= быть <, а именно char <short?

user3207158 11.11.2019 08:25

@ user3207158 Это отношение взято из стандарта. Он ничего не говорит об их битовой ширине, но гарантирует, что все размеры больше или равны предыдущим. char всегда меньше или равен short, ..., int всегда меньше или равен long и т. д. У меня нет стандарта под рукой, поэтому я не могу назвать эталонный банкомат.

Cole Johnson 12.11.2019 19:53

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

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

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

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

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

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

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

Просто для полноты и исторического интереса в мире 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

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

Другие вопросы по теме