我正在做一些C ++工作,要求我将“普通”(广泛使用)数据类型(例如int
)转换为固定大小的对位点,例如std::int32_t
。我有一些使用void*
的代码,但这会给我带来麻烦。
我知道任何给定指针的大小在给定系统上是相同的 - 为未来的读者编辑:有人指出大小没有保证,指针的绝对或相对。sizeof(void*) == sizeof(int*) == sizeof(short*) == sizeof(long*)
。但我也知道指针的大小可能因系统而异(特别是32位与64位)。
是否有固定大小的类型能够持有void*
?我认为std::intptr_t
或std::uintptr_t
是潜在的候选人,但我不确定哪个(如果有的话)是正确的。这主要是由于签字;我不确定为什么有intptr_t
的签名和无符号形式,因为我的印象不是指针的签名可以控制。 Instinct说我想要使用uintptr_t
,因为我不相信指针可以签名,但那时intptr_t
是什么?
关于我的需求的更多信息:我正在研究DLL,并且如果可能的话需要保证交叉编译器功能。对于基于整数的类型,这不是太糟糕;我可以将它们转换为幕后的std::intXX_t
类型。但我的DLL函数之一做了一些原始内存操作,需要返回void*
。我担心这会导致我遇到各种麻烦,如果我不能正确包装它,但我不知道用包裹它:我找不到任何排序保证指针的大小或数据范围。我知道内存本身可以在DLL外部访问;这不是问题。但是确保void*
可以安全地从主机EXE到达我的DLL,反之亦然,这是一个更大的问题。
答案 0 :(得分:5)
intptr_t和uintptr_t不是固定大小的类型,因此它们不足以满足您的声明目的。您特别要求"固定大小的类型能够持有void*
。"这不是100%可能的,因为我们不知道将来的系统会有什么样的指针大小(128位可能会在我们的生命周期内发生)。
我建议您使用uint64_t,然后添加static_assert(sizeof(void*) <= sizeof(uint64_t))
。有人可能会说,无法保证将void *放入uint64_t即使在断言通过的情况下也能在所有平台上运行,但我认为它对所有实际用途都足够好。
答案 1 :(得分:1)
我知道任何给定指针的大小在给定系统上是相同的
不一定。有char*
(和void*
)大于int*
的平台。
是否有固定大小的类型能够持有
void*
?
不,因为void*
的大小因平台而异。没有大于64位的(标准)固定大小类型,并且不能保证指针不会大于此值。
我认为
std::intptr_t
或std::uintptr_t
是潜在的候选人,但我不确定哪一个(如果有的话)是正确的。
它们都被指定为足以容纳任何指针值;但平台的大小可能会有所不同。根据您要对转换后的值进行算术运算(如果有),选择有符号或无符号。
答案 2 :(得分:1)
是否有相当于
void*
的固定大小?但我也知道指针的大小因系统而异(特别是32位与64位)。
总之,上述问题和声明意味着您不仅需要运行流程,而且需要跨流程甚至系统进行移植。您所能做的就是选择一个整体类型,至少与您想要支持的任何系统的最大尺寸一样长。无法保证任何特定尺寸都能永久保持,因此您只需选择您认为合理的尺寸。如果64对您而言足够,请查看您是否有定义uint64_t
的标题。
我认为std :: intptr_t或std :: uintptr_t是潜在候选人,但我不确定哪一个(如果有的话)是正确的。
这些大小基于正在运行的进程,并且不能保证足够大以容纳来自具有更宽指针大小的其他进程/系统的指针值。
内存地址永远不会消极,因此使用无符号类型是有意义的。可以对从一个存储器地址到另一个存储器地址的偏移进行签名,这就是为什么存在用于存储这种差异的签名类型....
答案 3 :(得分:1)
可以安全地假设即使在不同的编译器中,void*
也可以兼容相同的架构。
由于您的目标是DLL,并且您只能将DLL加载到具有相同体系结构的进程中,这应该足以保证互操作性。
答案 4 :(得分:0)
我正在创建一个程序,用于存储(在Java中)C ++中数据结构的本机指针。
由于我希望我的应用程序可移植,因此无论我的系统是否具有32位或64位架构,我都使用Java long(64位整数)来存储指针。
所以,我建议你将指针存储在int64_t变量中。
答案 5 :(得分:0)
如果您只关心内存大小,则可以intptr_t
和uintptr_t
。
如果你关心实际值或做一些算术,那么无符号的应该更好。
但两者都不是固定大小,它们的存储大小取决于实现。