sizeof (int) == sizeof (void *)?

Есть ли целочисленный тип с таким же размером, как указатель? Гарантировано для всех микроархитектур?

Согласно этой странице в Википедии , в C99 ваш заголовок stdint.h может объявлять intptr_t и uintptr_t, но тогда это, конечно, требует

  • C99
  • Разработчик компилятора, который решил реализовать эту необязательную часть стандарта

Так что в целом я считаю, что это сложно.

Проще говоря, нет. Не гарантируется на всех архитектурах.

Мой вопрос: почему? Если вы хотите выделить тип, достаточно большой для хранения void* , лучше всего выделить (на удивление достаточно 🙂 void* . Зачем нужно встраивать его внутри int ?

EDIT: на основе ваших комментариев к вашему дублирующему вопросу вы хотите сохранить специальные значения указателя (1,2,3), чтобы указать дополнительную информацию.

НЕТ !! Не делай этого !! , Нет никакой гарантии, что 1, 2 и 3 не являются вполне допустимыми указателями. Это может иметь место в системах, где вам необходимо выровнять указатели на 4-байтных границах, но, поскольку вы спросили обо всех архитектурах, я предполагаю, что у вас есть переносимость как высокая ценность.

Найдите другой способ сделать это правильно. Например, используйте объединение (синтаксис из памяти, возможно, неверный):

 typedef struct { int isPointer; union { int intVal; void *ptrVal; } } myType; 

Затем вы можете использовать isPointer ‘boolean’, чтобы решить, следует ли рассматривать союз как целое число или указатель.

РЕДАКТИРОВАТЬ:

Если скорость выполнения имеет первостепенное значение, то решение typedef – это путь. В принципе, вам нужно будет определить целое число, которое вы хотите для каждой платформы, на которой хотите работать. Вы можете сделать это с условной компиляцией. Я бы также добавил в проверку времени выполнения, чтобы убедиться, что вы правильно скомпилировали для каждой платформы (я определяю ее в источнике, но вы передадите это как флаг компилятора, например « cc -DPTRINT_INT »):

 #include  #define PTRINT_SHORT #ifdef PTRINT_SHORT typedef short ptrint; #endif #ifdef PTRINT_INT typedef int ptrint; #endif #ifdef PTRINT_LONG typedef long ptrint; #endif #ifdef PTRINT_LONGLONG typedef long long ptrint; #endif int main(void) { if (sizeof(ptrint) != sizeof(void*)) { printf ("ERROR: ptrint doesn't match void* for this platform.\n"); printf (" sizeof(void* ) = %d\n", sizeof(void*)); printf (" sizeof(ptrint ) = %d\n", sizeof(ptrint)); printf (" =================\n"); printf (" sizeof(void* ) = %d\n", sizeof(void*)); printf (" sizeof(short ) = %d\n", sizeof(short)); printf (" sizeof(int ) = %d\n", sizeof(int)); printf (" sizeof(long ) = %d\n", sizeof(long)); printf (" sizeof(long long) = %d\n", sizeof(long long)); return 1; } /* rest of your code here */ return 0; } 

В моей системе (Ubuntu 8.04, 32-бит) я получаю:

 ERROR: ptrint typedef doesn't match void* for this platform. sizeof(void* ) = 4 sizeof(ptrint ) = 2 ================= sizeof(short ) = 2 sizeof(int ) = 4 sizeof(long ) = 4 sizeof(long long) = 8 

В этом случае я бы знал, что мне нужно скомпилировать PTRINT_INT (или длинный). Может быть способ поймать это во время компиляции с #if, но я не мог быть обеспокоен этим исследованием в данный момент. Если вы нападаете на платформу, где нет целого типа, достаточного для удержания указателя, вам не повезло.

Имейте в виду, что использование специальных значений указателя (1,2,3) для представления целых чисел также может не работать на всех платформах – на самом деле это могут быть действительные адреса памяти для указателей.

Тем не менее, если вы проигнорируете мой совет, я не могу сделать, чтобы остановить вас. Это ваш код в конце концов :-). Одна из возможностей – проверить все возвращаемые значения из malloc, и если вы получите 1, 2 или 3, просто malloc снова (т. Е. Получим mymalloc (), который делает это автоматически). Это будет небольшая утечка памяти, но это не гарантирует никаких столкновений между вашими специальными указателями и реальными указателями.

Стандарт C99 определяет стандартные типы int:

7.18.1.4. Целочисленные типы, способные удерживать указатели объектов. Следующий тип обозначает целочисленный тип со знаком с тем свойством, что любой действительный указатель на void может быть преобразован в этот тип, а затем преобразован обратно в указатель на void, и результат будет сравниваться с исходный указатель:

  intptr_t 

Следующий тип обозначает целочисленный тип без знака с тем свойством, что любой действительный указатель на void может быть преобразован в этот тип, а затем преобразован обратно в указатель на void, и результат будет сравниваться с исходным указателем:

  uintptr_t 

Эти типы являются необязательными.

C99 также определяет size_t и ptrdiff_t:

Типы

  ptrdiff_t 

который является признанным целочисленным типом результата вычитания двух указателей;

  size_t 

который представляет собой целочисленный тип без знака результата оператора sizeof; а также

Архитектуры, которые я видел, имеют максимальный размер объекта, равный всей памяти, поэтому sizeof (size_t) == sizeof (void *), но я не знаю ничего, что переносимо на C89 (какой size_t является ) и гарантированно будет достаточно большим (что uintptr_t есть).

Это будет верно для стандартной 32-битной системы, но, безусловно, нет гарантий, и вы можете найти множество архитектур, где это не так. Например, распространенное заблуждение состоит в том, что sizeof (int) на x86_64 будет 8 (так как это 64-битная система, я думаю), а это не так. В x86_64 sizeof (int) все еще 4, но sizeof (void *) равно 8.

Так что насчет C ++. Должен ли я идти по следующим причинам:

 template  struct int_traits_t; template <> struct int_traits_t <16> {typedef uint16_t int_t;}; template <> struct int_traits_t <32> {typedef uint32_t int_t;}; template <> struct int_traits_t <64> {typedef uint64_t int_t;}; typedef int_traits_t ::int_t myintptr_t; 

просто чтобы получить портативное целое число указателя?

Стандартное решение этой проблемы – написать небольшую программу, которая проверяет размеры всех типов int (short int, int, long int) и сравнивает их с void *. Если есть совпадение, он испускает fragment кода, который определяет тип intptr. Вы можете поместить это в файл заголовка и использовать новый тип.

Это просто включить этот код в процесс сборки (например, с помощью make )

Нет, ближе всего вы придете к переносимому с помощью указателя целочисленному типу будут intptr_t и ptrdiff_t .

Нет.

Я не верю, что стандарт C даже определяет стандартные размеры . Объедините это со всеми архитектурами там (8/16/32 / 64bit и т. Д.), И нет никакого способа гарантировать что-либо.

int тип данных будет ответом на большинстве архитектур.

Но никто не гарантирует это для ЛЮБОЙ (микро) архитектуры.

Ответ кажется «нет», но если все, что вам нужно, это тип, который может действовать как оба, вы можете использовать объединение:

 union int_ptr_t { int i; void* p; }; 

Обычно sizeof (* void) зависит от ширины шины памяти (хотя необязательно – у pre-RISC AS / 400 была 48-разрядная адресная шина, но 64-разрядные указатели), а int обычно имеет такой же размер, как и регистр общего назначения процессора (есть также исключения – SGI C использовал 32-битные ints на 64-битном MIPS).

Таким образом, нет никакой гарантии.

Interesting Posts
Давайте будем гением компьютера.