Является ли intptr_t подписной копией uintptr_t (и наоборот)?

Я разрабатываю несколько тестов для класса MPL add_signed, который преобразует тип в его подписанный экземпляр. Он определяется следующим образом:

template<class T>
struct add_signed { 
    typedef T type;
};

template<>
struct add_signed<std::uint8_t> { 
    typedef std::int8_t type;
};

template<>
struct add_signed<std::uint16_t> { 
    typedef std::int16_t type;
};

template<>
struct add_signed<std::uint32_t> { 
    typedef std::int32_t type;
};

template<>
struct add_signed<std::uint64_t> { 
    typedef std::int64_t type;
};

При тестировании на разных типах я заметил, что следующее значение соответствует true:

std::is_same<add_signed<uintptr_t>::type, intptr_t>::value  // true

Аналогично для класса MPL add_unsigned следующий код оценивается как true:

std::is_same<add_unsigned<intptr_t>::type, uintptr_t>::value  // true

Мой компилятор - это MSVC 2010.

Итак, вопрос: можем ли мы предположить, что во всех (sane) компиляторах подписание intptr_t будет производить uintptr_t и наоборот?

Ответ 1

Типы intptr_t и uintptr_t являются необязательными в ISO/IEC 9899: 1999 (C99), но там, где они реализованы, так же как и другие. Все подписанные типы имеют неподписанный аналог одного и того же размера и наоборот.

§7.18.1 Целочисленные типы

Если определены имена typedef, отличающиеся только отсутствием или наличием начального u, они должны обозначать соответствующие типы подписей и без знака, как описано в 6.2.5; реализация, обеспечивающая один из этих соответствующих типов, также должна обеспечивать другую.

...

§7.18.1.4 Целые типы, способные удерживать указатели объектов

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

intptr_t

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

 uintptr_t

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

Обратите внимание, что в значении стандарта C функции не являются объектами; в стандарте C не гарантируется, что uintptr_t может содержать указатель на функцию.

К счастью, POSIX делает шаг к спасению: он требует, чтобы указатели на объекты и указатели функций были одинакового размера.

2.12.3 Типы указателей

Все типы указателей функций должны иметь то же представление, что и указатель типа на void. Преобразование указателя функции в void * не должно изменять представление. Значение void *, полученное в результате такого преобразования, может быть преобразовано обратно в исходный тип указателя функции с использованием явного приведения без потери информации.

Примечание:

Стандарт ISO C не требует этого, но он необходим для соответствия POSIX.