Есть ли переносимый способ узнать, определена ли uintptr_t в stdint.h?

Преамбула: я хочу преобразовать указатель в целочисленный тип, например. для проверки выравнивания. uintptr_t кажется правильным, но он гарантирован только в C, а не в С++ (или С++ 11)

Для следующего кода:

#include <stdint.h>
#ifndef I_WONDER_IF_UINTPR_T_IS_DEFINED
  typedef unsigned long uintptr_t;
#endif

template <typename T>
bool isAligned(unsigned char* p) ///Checks alignment with respect to some data type
{
   return !((uintptr_t) p % sizeof(T));
}

template bool isAligned<uint16_t>(unsigned char* p);
template bool isAligned<uint32_t>(unsigned char* p);
template bool isAligned<uint64_t>(unsigned char* p);

2 вопроса:

  • Есть ли волшебное и гарантированное слово, которое я могу использовать, где я положил I_WONDER_IF_UINTPR_T_IS_DEFINED?
  • Должен ли я просто использовать unsigned long и забыть об этом?

Сгенерированная сборка (при наличии uintptr_t): http://goo.gl/4feUNK

Примечание 1: Я знаю, чем в С++ 11 Я должен использовать alignof вместо sizeof
Примечание 2: Я знаю об этом обсуждении: <cstdint> vs < stdint.h >

Ответ 1

Если вы действительно хотите работать с реализацией, не предоставляющей uintptr_t при включении <stdint.h>, попробуйте вместо этого использовать uintmax_t и static_assert для удобства (вы уже установили, что вы можете быть в запутанной настройке, поэтому он может быть слишком мал):

#include <stdint.h>
static_assert(sizeof(uintmax_t) >= sizeof(void*), "need a bigger unsigned type.");

// Add code using `uintmax_t` to round-trip data-pointers here

Есть два недостатка:

  • uintmax_t может не быть uintptr_t, что важно для разрешения перегрузки и компоновки.
  • uintmax_t может быть больше, чем необходимо.

Ответ 2

В целом, портативные системы сборки на * nix имеют тенденцию использовать подход "autotools", который заключается в том, чтобы протестировать компиляцию тривиального файла, содержащего соответствующий тип, и, если он компилируется, вы знаете, что у вас есть этот тип. Если вы хотите что-то более простое, вы можете либо (a) предположить, что uintptr_t доступен даже в С++ (возможно, разумно), или (b) использовать unsigned long long, а затем:

static_assert(sizeof(unsigned long long) >= sizeof(void*), "oops");