是否存在与void*等效的固定大小

Is there a fixed-size equivalent to void*?

本文关键字:存在 void 是否      更新时间:2023-10-16

我正在做一些c++工作,这些工作需要我将"正常"(广泛使用的)数据类型(如int)转换为固定大小的对应类型(如std::int32_t)。我有一些使用void*的代码,然而,这给我带来了麻烦。

我知道任何给定指针的大小在给定的系统- sizeof(void*) == sizeof(int*) == sizeof(short*) == sizeof(long*)上是相同的。但是我也知道指针的大小会因系统而异(特别是32位和64位)。为将来的读者编辑:已经指出,指针的绝对或相对大小没有保证。

是否有一个固定大小的类型能够容纳void* ?我认为std::intptr_tstd::uintptr_t是潜在的候选人,但我不确定哪个(如果有的话)是正确的。这主要是由于签名;我不确定为什么intptr_t有符号和无符号形式,因为我不认为指针的签名是可以控制的。直觉告诉我,我想要使用uintptr_t,因为我不相信指针可以被签名,但是intptr_t有什么用呢?


关于我的需求的更多信息:我正在开发一个DLL,如果可能的话,需要保证交叉编译器的能力。对于基于整数的类型,这还不算太糟;我能够在幕后将它们转换为std::intXX_t类型。但是我的一个DLL函数做一些原始内存操作,需要返回一个void*。我担心这会给我带来各种各样的麻烦,如果我不能正确地包装它,但是我不知道用包装它:我无法找到任何关于指针大小或数据范围的保证。我知道一个事实,内存本身是可访问的外部DLL;这不是问题。但确保void*可以从主机EXE到我的DLL,反之亦然,安全是一个更大的问题。

intptr_t和uintptr_t不是固定大小的类型,因此它们将不足以满足您所述的目的。你特别要求"能够容纳void*的固定大小类型",这不是100%可能的,因为我们不知道未来的系统会有什么指针大小(128位很可能在我们的生命周期内发生)。

我建议你使用uint64_t,并添加一个static_assert(sizeof(void*) <= sizeof(uint64_t))。有人可能会说,没有保证把一个void*进入uint64_t将在所有平台上工作,即使在断言通过,但我认为这是足够好的所有实际用途。

我知道任何给定指针的大小在给定系统上都是相同的

不一定。有些平台的char*(和void*)大于int*

是否有固定大小的类型可以容纳void* ?

不,因为void*的大小在不同的平台上是不同的。没有大于64位的(标准)固定大小类型,也不能保证指针不会大于64位。

我认为std::intptr_tstd::uintptr_t是潜在的候选人,但我不确定哪个(如果有的话)是正确的。

它们都被指定为足够大,可以容纳任何指针值;但平台之间的规模可能有所不同。根据要对转换值执行的算术类型(如果有的话)选择有符号或无符号。

是否有与void*等效的固定大小?

但是我也知道指针的大小可以因系统而异(特别是32位和64位)。

上面的问题和陈述合在一起意味着您想要的不仅仅是运行中的进程,而是跨进程甚至系统的可移植。您所能做的就是选择一个至少与您想要支持的任何系统的最大大小一样长的整型。没有人能保证任何特定的尺寸永远持续下去,所以你只需要选择你认为合理的尺寸。如果64对你来说足够了,看看你是否有一个定义uint64_t的头文件。

我认为std::intptr_t或std::uintptr_t是潜在的候选人,但我不确定哪个(如果有的话)是正确的。

这些指针的大小是根据正在运行的进程而定的,不能保证足够大来容纳指针值,这些指针值来自其他具有更大指针大小的进程/系统。

内存地址永远不会是负的,所以使用unsigned类型是有意义的。从一个内存地址到另一个内存地址的偏移量可以被签名,这就是为什么有签名类型用于存储这种差异....

可以安全地假设,即使在不同的编译器中,void*将兼容相同的体系结构。

由于您的目标是一个DLL,并且您只能将DLL加载到具有相同体系结构的进程中,因此这应该足以保证互操作性。

我正在创建一个程序,用于(在Java中)存储指向c++数据结构的本地指针。

因为我希望我的应用程序是可移植的,所以我使用了一个Java长(64位整数)来存储指针,无论我的系统是32位还是64位架构。

因此,我建议您将指针存储在int64_t变量中。

如果您只是关心内存大小,intptr_tuintptr_t都是可能的。

如果你关心的是实际的值或者做一些算术运算,无符号的会更好。

但是它们都不是固定大小,它们的存储大小取决于实现。