Использование intptr_t вместо void *?

Хорошо ли использовать intptr_t в качестве хранилища общего назначения (для хранения указателей и целочисленных значений) вместо void*? (Как видно здесь: http://www.crystalspace3d.org/docs/online/manual/Api1_005f0-64_002dBit-Portability-Changes.html)

За что я уже читал:

  • intvoid*int roundtrip не гарантированно сохраняет исходное значение; Я думаю, intintptr_tint будет делать
  • арифметика указателя на void* и intptr_t требует отбрасывания, поэтому никто не получает преимущества здесь
  • void* означает менее явные приведения при хранении указателей, intptr_t означает меньшее количество приведений при сохранении целых значений
  • intptr_t требуется C99

Что еще я должен принять во внимание?

Ответ 1

Хорошо ли использовать intptr_t как хранилище общего назначения (для хранения указателей и целочисленных значений) вместо void*?

Нет.

intptr_t не гарантируется. Во-первых, как вы заметили, это было введено на C99. Во-вторых, реализациям не требуется иметь целочисленный тип, достаточно большой для хранения преобразованных значений указателя без потери информации.

Преобразование int в intptr_t и обратно вряд ли потеряет информацию, но нет реальной гарантии, что intptr_t шире, чем int.

Если вы хотите сохранить значения указателя, сохраните их в объектах указателя. Для чего предназначены объекты указателя.

Любой указатель на объект или неполный тип может быть преобразован в void* и обратно без потери информации. Для указателей на функции нет такой гарантии, но любой тип указателя на функцию может быть преобразован в любой другой тип указателя на функцию и обратно без потери информации. (Я имею в виду стандарт C, я думаю, что POSIX предоставляет некоторые дополнительные гарантии.)

Если вы хотите сохранить целое число или значение указателя в одном и том же объекте, первое, что вам нужно сделать, это пересмотреть свой дизайн. Если вы уже это сделали и пришли к выводу, что вы действительно этого хотите, подумайте об использовании объединения (и тщательно отслеживайте, какое значение вы сохранили в последнее время).

Существуют API, которые используют аргумент void* для передачи произвольных данных; см., например, функцию POSIX pthread_create(). Это можно оскорбить, добавив целочисленное значение в void*, но безопаснее передать адрес целочисленного объекта.

Ответ 2

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

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

union foo {
   int integer_foo;
   void *pointer_foo;
}

Это портативное устройство и позволяет хранить как разные вещи, так и размеры хранилища, необходимые для большего размера. Гарантируется, что он всегда будет работать.