C ++ by-reference参数和C链接

我遇到了一段代码(使用XLC8和MSFT9编译器),包含一个带有C链接和引用参数定义的函数的C ++文件。 这让我很烦,因为引用只是C ++。 有问题的函数是从C代码调用的,其中它被声明为将指针参数取代为相同类型而不是引用参数。

简化示例

C ++文件

extern "C" void f(int &i) { i++; } 

C档案

 void f(int *); int main() { int a = 2; f(&a); printf("%d\n", a); /* Prints 3 */ } 

现在,街上的一句话就是大多数C ++编译器,它们都像指针一样实现引用。 是这样的,只是纯粹的运气,这个代码工作的原因,或者它在C ++规范中的某处说,当你用引用参数和C链接定义一个函数时结果是什么? 我无法找到任何相关信息。

我的副本n3000.pdf(从这里开始 ),在7.5节 – 链接规范中有这个说法:

9 。 从C ++到其他语言中定义的对象以及从其他语言在C ++中定义的对象的链接是实现定义的并且依赖于语言。 只有在两种语言实现的对象布局策略足够相似的情况下才能实现这种联系。

由于C和C ++是不同的语言,这意味着你不能依赖常见编译器的这个“特性”。

更强的是同一部分中的注释5(强调我的):

如果两个声明声明具有相同名称的函数,并且参数类型列表(8.3.5)是同一命名空间的成员,或者声明具有相同名称的对象是同一命名空间的成员,并且声明为这些名称指定不同的语言链接,该计划是不正常的; 如果声明出现在不同的翻译单元中,则无需诊断

所以,我想说你所做的并不能保证按照标准工作,并且编译器不需要为你给出的例子打印诊断因为声明在不同的翻译单元中

仅供参考,在Snow Leopard上使用gcc和g ++版本4.2.1“对我有用”。

在许多情况下,但不是全部,可以使用“自动解除引用”指针实现引用。 在C ++标准中,任何特定的编译器都不会以这种方式处理具有C链接和引用参数的函数,您应该将其视为实现细节。

编写一个带指针并调用函数的转发函数并不难,如果你需要这样做而不依赖于实现细节:

 void real_f(int& n) { n++; } extern "C" void f(int* p) { // called from C code real_f(*p); } 

引用是对象的备用名称。 从技术上讲,C中没有任何东西可以直接映射到C ++引用。

引用的明显实现是作为(常量)指针,每次使用时都会解除引用。 因此,根据编译器如何实现引用,您的代码可能会起作用。 但这不正确。

解决方案是编写一个C函数,它接收一个真实对象或指向该对象的指针,并从中调用C ++函数。

我想你已经得到了一些很好的答案,所以只是在你的问题上指出一些额外的东西。

我的谦虚理解是,extern只是创造了一个C符号。

因此,即使我添加了一个类对象,你的例子仍然“似乎工作”(gcc / g ++) – 我不得不尝试相信它:

 class A {}; extern "C" void f(int &i, A a) { i++; } 

这就是Bjarne Stroustrup对引用的看法:

大多数引用是使用指针变量实现的实现;它通常占用一个内存字。但​​是,纯粹本地使用的引用可以 – 通常是 – 由优化器消除 ”。

例如:

  struct S { int a; int b[100]; }; // just an example void do_something(const vector& v) { for (int i=0; i 

在这种情况下,p不需要存储在存储器中(可能它只存在于寄存器中,也许它会消失在指令中)。