C++ 为64位和32位生成创建指针大小的联合
我想创建一个如下所示的联合C++ 为64位和32位生成创建指针大小的联合,c++,pointers,x86-64,32bit-64bit,unions,C++,Pointers,X86 64,32bit 64bit,Unions,我想创建一个如下所示的联合 union { long i; float f; void* ptr; }; 其中成员i和f始终是ptr的大小(float&long表示32位/double&long表示64位) 什么是用最小的宏使用来实现这一点? 注意,在UNISC++中,联合类型双关(写入一个成员,然后读取另一个)是未定义的行为。它在ISO C99中定义良好,并且在GNU C++中作为扩展。(还有一些C++编译器,我想包括MSVC),也要小心非平凡的可复制类型(具有构造函
union {
long i;
float f;
void* ptr;
};
其中成员i和f始终是ptr的大小(float&long表示32位/double&long表示64位)
什么是用最小的宏使用来实现这一点?
注意,在UNISC++中,联合类型双关(写入一个成员,然后读取另一个)是未定义的行为。它在ISO C99中定义良好,并且在GNU C++中作为扩展。(还有一些C++编译器,我想包括MSVC),也要小心非平凡的可复制类型(具有构造函数/析构函数)作为联合成员。< /P> 当然,除了类型双关(例如,手滚多态性)之外,还有一些其他的联合用法,类似这样的用法是有意义的
就是因为这个原因而存在的。(或者
intptr\u t
或者ptrdiff\u t
,如果出于某种原因您需要签名类型)
但是对于float
与double
相比,您需要预处理器uintpttr_MAX
提供了一种使用预处理器检查指针宽度的方法,这与sizeof(void*)
请注意,uintptr\u t
通常与指针的宽度相同,但类型名称定义为可以存储指针值的名称。对于32位平台上的floatptr\t
,情况并非如此。(有趣的事实:对于“规范”48位地址1,它将出现在x86-64上)。如果这让你感到困扰,或者你担心它会扭曲你对uintpttr\t
的看法,请选择一个不同的名称floatptr_t
是短的,看起来是对的,即使它是“错的”
从而确认联盟本身和每个成员都具有预期的规模
MSVC也可以工作,编译为int size\u f DD 08H
或04H
等等
脚注1:在x86-64上,规范虚拟地址是扩展到64的48位符号,因此您实际上可以通过
intptr\t
->double
转换往返指针值,而不会出现舍入错误。但对于不至少2字节对齐的高半地址,不能使用uintpttr\t
->double
。(如果没有AVX512F,uint64的转换速度很慢。)
在当前硬件上,非规范虚拟地址出现故障
在32位模式下,线性地址限制为32位。PAE允许多个32位进程各自使用不同4GB的物理内存,但seg:off->32位线性在页表查找之前发生。使用48位
seg:off
地址并不能获得更大的地址空间,因此编译器不会这样做。32位指针是seg:off
地址的off
部分,段基固定为零,因此它们与线性虚拟地址相同。与64位模式相同,64位偏移。 注意,在UNISC++中,联合类型双关(写入一个成员,然后读取另一个)是未定义的行为。它在ISO C99中定义良好,并且在GNU C++中作为扩展。(还有一些C++编译器,我想包括MSVC),也要小心非平凡的可复制类型(具有构造函数/析构函数)作为联合成员。< /P> 当然,除了类型双关(例如,手滚多态性)之外,还有一些其他的联合用法,类似这样的用法是有意义的
就是因为这个原因而存在的。(或者
intptr\u t
或者ptrdiff\u t
,如果出于某种原因您需要签名类型)
但是对于float
与double
相比,您需要预处理器uintpttr_MAX
提供了一种使用预处理器检查指针宽度的方法,这与sizeof(void*)
请注意,uintptr\u t
通常与指针的宽度相同,但类型名称定义为可以存储指针值的名称。对于32位平台上的floatptr\t
,情况并非如此。(有趣的事实:对于“规范”48位地址1,它将出现在x86-64上)。如果这让你感到困扰,或者你担心它会扭曲你对uintpttr\t
的看法,请选择一个不同的名称floatptr_t
是短的,看起来是对的,即使它是“错的”
从而确认联盟本身和每个成员都具有预期的规模
MSVC也可以工作,编译为int size\u f DD 08H
或04H
等等
脚注1:在x86-64上,规范虚拟地址是扩展到64的48位符号,因此您实际上可以通过
intptr\t
->double
转换往返指针值,而不会出现舍入错误。但对于不至少2字节对齐的高半地址,不能使用uintpttr\t
->double
。(如果没有AVX512F,uint64的转换速度很慢。)
在当前硬件上,非规范虚拟地址出现故障
在32位模式下,线性地址限制为32位。PAE允许多个32位进程各自使用不同4GB的物理内存,但seg:off->32位线性在页表查找之前发生。使用48位
seg:off
地址并不能获得更大的地址空间,因此编译器不会这样做。32位指针是seg:off
地址的off
部分,段基固定为零,因此它们与线性虚拟地址相同。与64位模式下的64位偏移量相同。听起来有点像。听起来有点像。uintpttr\u t
表示可以存储指针值的uint。。。很难说floatptr\t
是否也能满足这一保证1UL@M.M:Good catch。我用1all
修复了它,它保证至少是64位,因此足够大,可以表示2^32
。移动两次可避免UB,但可能导致0
。我只是在用x86-64模式运行的编译器进行测试
#include <stdint.h>
// assumption: pointers are 32 or 64 bit, and float/double are IEEE binary32/binary64
#if UINTPTR_MAX > (1ULL<<32)
typedef double floatptr_t;
#else
typedef float floatptr_t;
#endif
static_assert(sizeof(floatptr_t) == sizeof(void*), "pointer width doesn't match float or double, or our UINTPTR_MAX logic is wrong");
union ptrwidth {
uintptr_t u;
intptr_t i;
floatptr_t f;
void *ptr;
};
int size = sizeof(ptrwidth);
int size_i = sizeof(ptrwidth::i);
int size_f = sizeof(ptrwidth::f);
int size_ptr = sizeof(ptrwidth::ptr);
# gcc -m32 output
size_ptr: .long 4
size_f: .long 4
size_i: .long 4
size: .long 4
# gcc -m64 output
size_ptr: .long 8
size_f: .long 8
size_i: .long 8
size: .long 8