将包含32位值的UINT64_T传递给其参数实际上是UINT32_T的外部函数是否安全?
我正在研究一个跨平台程序,该程序调用带有C链接的动态库中的函数。我需要支持此动态库的多个版本,但是在我需要支持的两个版本之间,有一个函数参数已从uint32_t
更改为uint64_t
。
如果我通过此函数A uint64_t
包含仍然可以表示为UINT32_T的值,即使函数的参数实际上是uint32_t
,也可以安全地执行吗?
更具体地说:
如果将函数的源编译到动态库中是:
extern "C" void foo(uint32_t param) {
...
}
我可以这样使用该函数安全:
extern "C" void foo(uint64_t);
uint32_t value32 = 10; // Ensure value can be represented by uint32_t
uint64_t value64 = value32;
foo(value64);
如果是,是否可以安全地在不同的平台上执行此操作?我的程序支持32位和64位窗口(两者都汇编为X86),X86_64 MacOS,ARM64 MACOS,X86 Linux和X86_64 Linux。
I'm working on a cross-platform program that calls a function from a dynamic library with C linkage. I need to support multiple versions of this dynamic library, but between two of the versions I need to support, there is a function parameter that has changed from uint32_t
to uint64_t
.
If I pass this function a uint64_t
that contains value which is still representable as a uint32_t, is that safe to do even when the function's parameter is actually a uint32_t
?
Put more specifically:
If the source of the function as compiled into the dynamic library is:
extern "C" void foo(uint32_t param) {
...
}
Is it safe for me to use the function like so:
extern "C" void foo(uint64_t);
uint32_t value32 = 10; // Ensure value can be represented by uint32_t
uint64_t value64 = value32;
foo(value64);
If yes, is it safe to do this across different platforms? This program of mine supports 32-bit and 64-bit Windows (compiled as x86 for both), x86_64 macOS, arm64 macOS, x86 Linux, and x86_64 Linux.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不,这是非法的。 C ++ 20 [basic.link] P11:
此外,它实际上将使用通常的基于堆栈的呼叫约定在32位X86系统上失败。用
uint32_t
定义的功能将在堆栈上寻找一个dword,但将推开两个字样。然后上面的任何论点都将位于错误的位置。 stdcall惯例中,所谓的函数会弹出自己的论点,这甚至更糟。它会弹出错误的数量,不平衡堆栈,并在返回后引起各种混乱。No, this is illegal. C++20 [basic.link] p11:
Moreover, it will actually fail on 32-bit x86 systems using the usual stack-based calling conventions. The function defined with
uint32_t
will be looking for one dword on the stack, but two will have been pushed. Any arguments above it will then be in the wrong place. It's even worse with the stdcall convention, in which the called function pops its own arguments; it will pop the wrong amount, unbalance the stack, and cause all sorts of mayhem after returning.我敢肯定,有人会用一些人为的示例进行操作,但在英特尔系统上,请记住,较大的寄存器是在较小的寄存器上构建的(
rax
是通过<构建的代码> eax ,它是通过ax
和al
)构建的,因此您要做的事情将有效。I'm sure someone will pipe in with some contrived example of a system where this won't work, but on Intel systems remember that larger registers are built on top of smaller ones (
rax
is built overeax
, which is built overax
andal
), and so what you're trying to do will work.