c++ - 在 C++ 程序中使用 C 链接时参数丢失

标签 c++ c visual-studio-2013

我在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

我有三个问题:

  1. 不应该有一个编译器错误指示参数数量不匹配吗?
  2. 在上面的场景中,由于字符串hello 没有被bar 接收到,它何时以及如何销毁?
  3. 如上编写和使用代码是否完全有效(知道参数将被删除)?参数删除背后的语义到底是什么?

最佳答案

虽然您指定的是 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/

相关文章:

c++ - 如何从 PathCompactPath 的 Wnd 句柄获取 DC 句柄?

c++ - 如何使用标志参数创建函数? (C++)

c - 如何获得每个堆的起始地址?

c - pthread_create() 调用的函数有多个参数?

javascript - 从 MSBuild SonarQube Runner Analysis 中删除单个 JavaScript 文件

c++ - STL 字符串类中的运算符 char*

c++ - 排序多维数组并保持索引 C++

c - semop : Bad file descriptor

mysql - 在 Visual Basic 中使用 mysql 时出现连接错误

c# - 禁止不带代码的警告