C++ 引用参数和 C 链接

问题描述 投票:0回答:5

我遇到了一段工作代码(使用 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 链接的函数时的结果是什么?我没找到这方面的信息。

c++ c pointers reference
5个回答
12
投票

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

如果您需要在不依赖实现细节的情况下执行此操作,那么编写一个接受指针并调用您的函数的转发函数并不难:

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

5
投票

我的 n3000.pdf 副本(来自此处),在第 7.5 节中有这样的说法—链接规范

9。从 C++ 到中定义的对象的链接 其他语言和定义的对象 在其他语言的 C++ 中是 实现定义的和 依赖于语言。仅当 两种对象布局策略 语言实现类似 实现这样的联动就足够了。

由于 C 和 C++ 是不同的语言,这意味着你不能依赖通用编译器的这个“功能”。

同一节中的注释 5 更强(强调我的):

如果两个声明声明了函数 具有相同的名字和 参数类型列表(8.3.5)为 同一命名空间的成员或 声明具有相同名称的对象 是同一命名空间的成员并且 声明给出了名称 不同语言之间的联系, 程序格式不正确; 无诊断 如果出现声明则需要 在不同的翻译单位.

因此,我想说,您所做的并不能保证按照标准工作,并且编译器不需要为您给出的示例打印诊断信息,因为声明位于不同的翻译单元中

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


4
投票

我认为您已经得到了一些很好的答案,因此只需指出您问题上的一些额外内容即可。

我的粗浅理解是 extern 只是创建一个 C 符号。

所以即使我添加一个类对象,你的示例仍然“似乎有效”(gcc/g++) - 我必须尝试相信它:

class A {};

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

3
投票

A reference 是对象的替代名称。从技术上讲,C 中没有任何内容可以直接映射到 C++ 引用。

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

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


0
投票

这就是 Bjarne Stroustrup 关于参考文献的说法:

大多数引用都是使用指针变量实现的;引用通常占用一个内存字。但是,纯粹本地使用的引用可以(而且经常)被优化器消除”。

例如:

 struct S 
 { 
    int a;
    int b[100]; 
 };  // just an example

 void do_something(const vector<S>& v)
 {
    for (int i=0; i<v.size(); ++i)
    {
        int(&p)[100] = v[i].b;
        for (int j=0; j<100; ++j) 
           cout <<p[j];
    }
 }

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

© www.soinside.com 2019 - 2024. All rights reserved.