我在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 样式调用约定来引用未在该编译单元中定义的符号。然后,编译器生成一个对象,告诉链接器“在此处调用 _bar
”(可能是 bar
,具体取决于您的平台),它很乐意解析为 的编译输出bar.cpp
。较旧的 C++ 调用约定会导致损坏的名称,例如 barZ8intZP8char
或更糟,这取决于您的编译器,以确保重载正常工作。然而,较新的编译器可能更智能(神奇!)并且可能理解存储在目标文件中的其他元数据。
多平台代码的一个更大问题与堆栈排序有关。在一些平台上,参数以与其声明相反的顺序存储在堆栈中,因此您的代码将提供字符串地址而不是整数值。打印一个整数很好,但会导致(希望)出现段错误,第一个参数是字符串,第二个参数是函数声明中的整数。
2.) 这取决于您使用的平台。对于大多数与 IA32 系统(x86、AMD64、IA64 等)相关的平台,调用者负责管理堆栈上的参数。因此,当调用完成时,包含额外参数的堆栈帧将被完全丢弃。在某些优化案例中,这可能会触发一个离散错误,其中一个框架被重用,因为编译器被错误告知了调用堆栈。
3.) 对于应用程序编程,我认为这是一种不好的做法,因为它可能会引入非常难以诊断的错误。我敢肯定有人已经找到了关于二进制兼容性的声明的边缘案例;然而,我更希望编译器了解参数以避免 #2 中提到的优化错误。
关于c++ - 在 C++ 程序中使用 C 链接时参数丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28598552/