Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

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

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

Так что, в общем, я думаю, что это тяжело.

Ответ 2

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

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

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

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

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

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

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

EDIT:

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

#include <stdio.h>
#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(), который делает это автоматически). Это будет небольшая утечка памяти, но это не гарантирует никаких столкновений между вашими специальными указателями и реальными указателями.

Ответ 3

Стандарт 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 есть).

Ответ 4

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

Ответ 5

А как насчет С++. Должен ли я идти по длине:

template <int BITS> 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 <sizeof (void*) * 8>::int_t myintptr_t;

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

Ответ 6

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

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

Ответ 7

Нет, ближайший вы попадете в переносимый целочисленный тип с указателем, будет intptr_t и ptrdiff_t.

Ответ 8

Нет.

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

Ответ 9

Тип данных

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

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

Ответ 10

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

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

Ответ 11

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

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