我正在为add_signed MPL类开发一些测试,它将类型转换为已签名的对应类型。它的定义如下:
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
对于add_unsigned MPL类,以下代码的计算结果为true:
std::is_same<add_unsigned<intptr_t>::type, uintptr_t>::value // true
我的编译器是MSVC 2010。
所以问题是 - 我们可以假设在所有(理智的)编译器中签名intptr_t会产生uintptr_t,反之亦然吗?
答案 0 :(得分:19)
类型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
以下类型指定无符号整数类型,其属性为any 指向void的指针可以转换为这种类型,然后转换回指向void的指针, 并且结果将与原始指针进行比较:
uintptr_t
这些类型是可选的。
请注意,在C标准的含义范围内,函数不是对象; C标准不保证uintptr_t
可以保存函数指针。
幸运的是,POSIX步骤拯救:它确实需要对象指针和函数指针的大小相同。
2.12.3指针类型
所有函数指针类型应与
void
的类型指针具有相同的表示形式。将函数指针转换为void *
不得改变表示。这种转换产生的void *
值可以使用显式转换转换回原始函数指针类型,而不会丢失信息。注意:
ISO C标准不要求这样做,但它是POSIX一致性所必需的。