在 C++ 程序中使用 C 链接时参数丢失
parameter dropping when using C linkage in a C++ program
我在main.cpp
中有以下代码
extern "C"
{
void bar(int x, char* s);
}
int main()
{
bar(5, "hello");
}
请注意,函数 bar
被声明为采用两个参数。然后将其编译并链接到包含此代码
的静态库bar.cpp
#include <iostream>
extern "C"
{
void bar(int x)
{
std::cout << x;
}
}
通知函数bar
只有一个参数。
可执行文件编译成功并打印5
我有三个问题:
- 不应该有一个编译器错误指示参数数量不匹配吗?
- 在上面的场景中,由于字符串
hello
没有被bar
接收到,它是什么时候以及如何销毁的?
- 像上面那样编写和使用代码是否完全有效(知道参数会被丢弃)?参数删除背后的语义到底是什么?
虽然您指定了 VS,但问题的回答一般是关于 C++、编译器和执行平台的。
1.) 您指示编译器遵循适用于您平台的 C 样式调用约定来引用未在该编译单元中定义的符号。编译器然后生成一个对象,它告诉链接器 "call _bar
here"(可能是 bar
,具体取决于您的平台),它愉快地解析为 bar.cpp
的编译输出。较旧的 C++ 调用约定会导致名称混乱,例如 barZ8intZP8char
或更糟,具体取决于您的编译器,以确保重载正常工作。然而,较新的编译器可能更聪明(神奇!)并且可能理解存储在目标文件中的其他元数据。
多平台代码的一个更大问题与堆栈排序有关。在一些平台上,参数以与其声明相反的顺序存储在堆栈中,因此您的代码将提供字符串地址而不是整数值。打印一个整数很好,但会导致(希望)一个段错误,第一个参数是一个字符串,第二个是函数声明中的一个整数。
2.) 这取决于您使用的平台。对于大多数与 IA32 系统(x86、AMD64、IA64 等)相关的平台,调用者负责管理堆栈上的参数。因此,当调用完成时,包含额外参数的堆栈帧将被完全丢弃。在某些优化案例中,这可能会触发一个离散错误,其中一个框架被重用,因为编译器在调用堆栈方面被误导了。
3.) 对于应用程序编程,我认为这是一种不好的做法,因为它可能会引入非常难以诊断的错误。我敢肯定有人已经找到了关于二进制兼容性的声明的边缘案例;但是我更希望编译器知道参数以避免#2 中提到的优化错误。
我在main.cpp
extern "C"
{
void bar(int x, char* s);
}
int main()
{
bar(5, "hello");
}
请注意,函数 bar
被声明为采用两个参数。然后将其编译并链接到包含此代码
bar.cpp
#include <iostream>
extern "C"
{
void bar(int x)
{
std::cout << x;
}
}
通知函数bar
只有一个参数。
可执行文件编译成功并打印5
我有三个问题:
- 不应该有一个编译器错误指示参数数量不匹配吗?
- 在上面的场景中,由于字符串
hello
没有被bar
接收到,它是什么时候以及如何销毁的? - 像上面那样编写和使用代码是否完全有效(知道参数会被丢弃)?参数删除背后的语义到底是什么?
虽然您指定了 VS,但问题的回答一般是关于 C++、编译器和执行平台的。
1.) 您指示编译器遵循适用于您平台的 C 样式调用约定来引用未在该编译单元中定义的符号。编译器然后生成一个对象,它告诉链接器 "call _bar
here"(可能是 bar
,具体取决于您的平台),它愉快地解析为 bar.cpp
的编译输出。较旧的 C++ 调用约定会导致名称混乱,例如 barZ8intZP8char
或更糟,具体取决于您的编译器,以确保重载正常工作。然而,较新的编译器可能更聪明(神奇!)并且可能理解存储在目标文件中的其他元数据。
多平台代码的一个更大问题与堆栈排序有关。在一些平台上,参数以与其声明相反的顺序存储在堆栈中,因此您的代码将提供字符串地址而不是整数值。打印一个整数很好,但会导致(希望)一个段错误,第一个参数是一个字符串,第二个是函数声明中的一个整数。
2.) 这取决于您使用的平台。对于大多数与 IA32 系统(x86、AMD64、IA64 等)相关的平台,调用者负责管理堆栈上的参数。因此,当调用完成时,包含额外参数的堆栈帧将被完全丢弃。在某些优化案例中,这可能会触发一个离散错误,其中一个框架被重用,因为编译器在调用堆栈方面被误导了。
3.) 对于应用程序编程,我认为这是一种不好的做法,因为它可能会引入非常难以诊断的错误。我敢肯定有人已经找到了关于二进制兼容性的声明的边缘案例;但是我更希望编译器知道参数以避免#2 中提到的优化错误。