将包含 32 位值的 uint64_t 传递给参数实际上是 uint32_t 的外部函数是否安全?
Is it safe to pass a uint64_t containing a 32-bit value to an external function whose parameter is actually a uint32_t?
我正在开发一个跨平台程序,该程序使用 C 链接从动态库调用函数。我需要支持这个动态库的多个版本,但是在我需要支持的两个版本之间,有一个函数参数从uint32_t
变成了uint64_t
。
如果我向此函数传递一个 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 位 Windows(两者都编译为 x86)、x86_64 macOS、arm64 macOS、x86 Linux 和 x86_64 Linux.
我敢肯定有人会输入一些人为的系统示例,但在 Intel 系统上,请记住较大的寄存器构建在较小的寄存器之上(rax
eax
,它建立在 ax
和 al
) 之上,因此您尝试做的事情会起作用。
不,这是非法的。 C++20 [basic.link] p11:
After all adjustments of types (during which typedefs (9.2.3) are replaced by their definitions), the types
specified by all declarations referring to a given variable or function shall be identical.
此外,它实际上会在使用通常的 stack-based 调用约定的 32 位 x86 系统上失败。用 uint32_t
定义的函数将在堆栈中查找一个双字,但两个双字将被压入。它上面的任何参数都会出现在错误的位置。对于 stdcall 约定,情况更糟,在该约定中,被调用函数会弹出自己的参数;它会弹出错误的数量,使堆栈不平衡,并在返回后造成各种混乱。
我正在开发一个跨平台程序,该程序使用 C 链接从动态库调用函数。我需要支持这个动态库的多个版本,但是在我需要支持的两个版本之间,有一个函数参数从uint32_t
变成了uint64_t
。
如果我向此函数传递一个 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 位 Windows(两者都编译为 x86)、x86_64 macOS、arm64 macOS、x86 Linux 和 x86_64 Linux.
我敢肯定有人会输入一些人为的系统示例,但在 Intel 系统上,请记住较大的寄存器构建在较小的寄存器之上(rax
eax
,它建立在 ax
和 al
) 之上,因此您尝试做的事情会起作用。
不,这是非法的。 C++20 [basic.link] p11:
After all adjustments of types (during which typedefs (9.2.3) are replaced by their definitions), the types specified by all declarations referring to a given variable or function shall be identical.
此外,它实际上会在使用通常的 stack-based 调用约定的 32 位 x86 系统上失败。用 uint32_t
定义的函数将在堆栈中查找一个双字,但两个双字将被压入。它上面的任何参数都会出现在错误的位置。对于 stdcall 约定,情况更糟,在该约定中,被调用函数会弹出自己的参数;它会弹出错误的数量,使堆栈不平衡,并在返回后造成各种混乱。