c89: конвертировать int в void * и обратно - PullRequest
7 голосов
/ 12 августа 2011

Во-первых, это не обман:

Безопасно ли приводить int к пустому указателю и снова возвращаться к int?

Разница в вопросах заключается в следующем: я использую только void * для хранения int, но я никогда не использую его как void *.

Таким образом, вопрос действительно сводится к этому:

Является ли пустота * такой же шириной, как int

Я не могу использовать intptr_t, потому что я использую c89 / ANSI C.

EDIT

В stdint.h из C99 (версия gcc) я вижу следующее:

/* Types for `void *' pointers.  */
#if __WORDSIZE == 64
# ifndef __intptr_t_defined
typedef long int        intptr_t;
#  define __intptr_t_defined
# endif
typedef unsigned long int   uintptr_t;
#else
# ifndef __intptr_t_defined
typedef int         intptr_t;
#  define __intptr_t_defined
# endif
typedef unsigned int        uintptr_t;
#endif

Могу ли я просто сделать что-то похожее на Джерри и ожидать, что это сработает? Казалось бы, приведение должно работать, поскольку все intptr_t является typedef для целочисленного типа ...

Ответы [ 4 ]

9 голосов
/ 12 августа 2011

Нет, это не гарантируется, чтобы быть безопасным.

В стандарте C99 есть следующее (раздел 6.3.2.3):

Целое число может быть преобразовано в любой указательтип.За исключением случаев, указанных ранее, результат определяется реализацией, может быть неправильно выровнен, может не указывать на объект ссылочного типа и может быть представлением прерывания.

Любой тип указателя может быть преобразован вцелочисленный тип.За исключением случаев, указанных ранее, результат определяется реализацией.Если результат не может быть представлен в целочисленном типе, поведение не определено.Результат не обязательно должен находиться в диапазоне значений любого целочисленного типа.

Я вполне уверен, что pre-C99 не будет отличаться.

1 голос
/ 26 октября 2017

FreeRTOS сохраняет идентификаторы таймера в Timer_t как void * pvTimerID. Поэтому при использовании этого в качестве пространства хранения, а НЕ указателя на что-либо, необходимо привести его к чему-то, что может быть использовано, например, в качестве индекса массива.

чтобы прочитать идентификатор, сохраненный как пустота *:

void* pvId = pxTimer->pvTimerID; int index = (int)(pvId - NULL);

1 голос
/ 12 августа 2011

Вот портативная альтернатива.

static const char dummy[MAX_VALUE_NEEDED];
void *p = (void *)(dummy+i); /* cast to remove the const qualifier */
int i = p-dummy;

Конечно, это может тратить чрезмерно большие объемы виртуального адресного пространства, если вам нужны большие значения, но если вы просто хотите передать маленькие целые числа, это на 100% переносимо.и чистый способ хранить целочисленные значения в void *.

1 голос
/ 12 августа 2011

Существует C FAQ: Могу ли я временно вставить целое число в указатель или наоборот? .

Самый чистый ответ: нет, это небезопасно, избегайте этого и продолжайте. Но POSIX требует, чтобы это было возможно. Таким образом, является безопасным в POSIX-совместимых системах.

...