C++的Extern / 多重定义问题

3
我是一名能够翻译文本的助手。
我正在尝试使用externs在C++中与Ada进行接口交互。这两种实现方式有什么区别? 实现方案A
namespace Ada
{
    extern "C"
    {
        int getNumber();
        int index;
        int value;
    }
}

实施方案B

namespace Ada
{
    extern "C"
    {
        int getNumber();
    }
    extern "C" int index;
    extern "C" int value;
}

这两个实现都可以编译通过。但是Impl-A在链接时失败了,我得到了一个关于indexvalue的多重定义错误。我只是想了解它们之间的区别。

3个回答

7
一个应用于大括号内的声明序列的链接说明符(即extern "C"extern "C++")对于封闭的声明是否是定义没有影响,然而应用于单个声明的链接说明符被视为一个extern说明符,用于确定声明是否也是一个定义。(来自C++03的7.5段第7句话)。
因此:
extern "C" { int a; } // a is declared and defined

extern "C" int a; // a is just a declaration (as if extern int a;)

extern "C" int a = 0; // a is a definition because of the initializer.

7
extern "C"只传达了extern "C"块内代码使用的链接约定。 在该块中的任何内容将被链接为纯c语言。 令人困惑的是,extern int完全不同。 它意味着您保证确实存在一个名为index的实际int和一个名为value的实际int,但它们在此处无法找到。 在您的implementation-A中,第二个意义上的int实际上不是外部的 - extern "C"仅意味着它们提供严格的c语言链接约定。 相同的关键字但完全不同的用途,这很不幸,因为它会导致像这样奇怪的问题。 混合使用它们是合法的(显然),但它们在一起的行为方式与其名称所暗示的不同。
编辑
请参见Charles的响应,以获取C ++标准中定义的extern奇怪性的真正定义。

1
@Peter:我也是这么想的,但这仍然没有解释为什么代码的第二个版本能够工作。 - sbi
@sbi 我不确定我已经充分测试过第二个是否有效...只是它链接了。 - Jerunh
1
我已经读了这个答案几次,但我不理解在单个声明中应用extern "C"和在大括号包含的声明列表中应用extern "C"之间的区别(例如)。显然我错了(因为它已被接受),但我没有看到它如何回答原始问题。 - CB Bailey
@charles - 哎呀,不好意思,我本来是想提到实现-B的。实际上,我更喜欢你的回答,因为它引用了参考文献。我的回答只是试图解释为什么第一个实现方法不起作用,但没有解释为什么第二个实现方法可以。 - Peter

3
我不确定第二种方法为什么有效,但你需要使用


namespace Ada
{
    extern "C"
    {
        int getNumber();
        extern int index;
        extern int value;
    }
}

因为您只想声明indexvalue,而不是定义它们。(有关区别,请参见此答案。)

第二个可能有效,因为 extern "C" 对于变量没有任何意义,所以 "C" 被忽略了?这只是一个猜测。 - Oliver Charlesworth
我认为更一般的问题是为什么extern块没有为所有内容设置extern。 - linuxuser27
1
@linuxuser:不应该。extern "blah" T foo只是告诉链接器为链接foo而遵循的链接约定。另一方面,extern T bar告诉编译器不必担心bar的存在,链接器会(希望)在某个地方找到一个。后者将使用(隐式的)“C++”链接。 - sbi
@Oli:我认为C++实现将变量类型编码到其名称中是很常见的,而C则不是。因此,extern "C" int x确实有作用:它请求链接器使用C的链接方式来查找x - sbi
1
@Oli,变量名被混淆几乎是必须的。这与它们的类型无关,主要与它们的命名空间有关。如果它们没有被混淆,如何区分::indexAda::indexextern "C"意味着它们没有被区分,但实际上声明了相同的对象。 - Johannes Schaub - litb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接