外部链接和»extern“C”«块

时间:2014-05-27 13:41:20

标签: c++ c

我有一个int ID,我想在C ++中定义并提供C链接(为了简单起见,设计案例):

/* i.h */
#ifdef __cplusplus
extern "C" {
#endif
        extern int ID;
#ifdef __cplusplus
}
#endif

这是使用int

的C和C ++程序
/* m.cpp */
#include "i.h"
#include <iostream>
int main() { std::cout << ID << std::endl; }

/* m.c */
#include "i.h"
#include <stdio.h>
int main() { printf("%d\n", ID); }

现在我想知道的是extern "C"和/或extern的语法。以下是int ID可以和不可以定义的方式:

/* i.cpp */
//                     const int ID = 88;   // no C linkage, obviously, LNK2019/1120
// extern "C"          const int ID = 88;   // provides C linkage
// extern "C" {        const int ID = 88; } // no C linkage, surprisingly, LNK2019/1120
// extern "C" { extern const int ID = 88; } // C linkage restored

编译:

cl /nologo /W4 m.cpp i.cpp /MD /EHsc
cl /nologo /W4 m.c   i.cpp /MD

我不明白的是extern "C"{block}一起使用时的语法。我必须重复extern,而使用extern "C"的无块形式我不会。这只是一个语法怪癖还是还有更多呢?

我在Dale Rogerson的 Inside COM 第98页偶然发现了这个问题。有一个嵌套extern的代码清单和一条旨在澄清的评论(但我不明白):

#include <objbase.h>
extern "C"{
  extern const IID IID_IX = {0x32bb8320, 0x41b, 0x11cf, ...};
  // The extern is required to allocate memory for C++ constants.
}

任何人都可以解释内部extern吗?

3 个答案:

答案 0 :(得分:3)

内部extern表示预期:&#34;符号在其他地方定义,它具有外部链接,不在此单元中为其分配空间(除非在此定义)&#34;。

外部extern "C" { ... }可能有一点误导性的语法,它只告诉编译器&#34;如果你在这个块里面用外部链接创建任何符号的名称,请使用传统的C命名( C语言链接)而不是C ++名称修改( C ++语言链接)为他们&#34;。但它没有指明块内的所有内容都是在其他地方定义的#34; (具有外部链接) - 它们仍然使用默认的内部链接进行声明。这就是你需要内部extern的原因。

单行变体extern "C" <variable declaration>只是一个简写,因为如果你关心它的跨单位符号名称,你可能想要定义一个外部变量。

(作为旁注,我还会在i.h中加入i.cpp,这样我就不用再记得在实施中再混淆extern "C"了。)

答案 1 :(得分:2)

问题在于constextern互相交战。 const表示(除其他外),&#34;将此定义设为内部定义,除非其上有明确的extern。&#34;。当定义位于extern "C"块中时,定义上没有extern 直接,因此&#34;隐含内部&#34;来自const优先。其他定义都直接在定义上有extern,因此它变为外部。

答案 2 :(得分:1)

  

以下是int ID的定义方式:

小心! extern "C"在不同的环境中有不同的效果。

N3797§7.5/ 7:

  

直接包含在 linkage-specification 中的声明被处理   就好像它包含extern说明符(7.1.1)一样   确定声明的名称与是否为a的链接   定义即可。此类声明不应指定存储类别。

extern "C" int i; // declaration
extern "C" {
    int i;           // definition
}

因此,您的代码段中的第二行只是一个声明,而您的第三行也是一个定义。这会改变 linkage-specification 对声明的影响 - 您不能在C ++转换单元C链接中指定名称。你必须把它作为一个纯粹的宣言。