外部链接和"外部"C""块

External linkage and »extern "C"« block

本文关键字:外部 链接      更新时间:2023-10-16

我有一个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("%dn", 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 ?

内部的extern意味着所期望的:"该符号是在其他地方定义的,它有外部链接,不要在本单元中为它分配空间(除非这里也定义了)"。

外部extern "C" { ... }可能有点误导语法,它只告诉编译器"如果您在此块内创建具有外部链接的任何符号的名称,请使用传统的C命名(C语言链接)而不是c++名称混淆( c++语言链接)"。但是它没有指定块内的所有内容都"在其他地方定义"(具有外部链接)——它们仍然使用默认的内部链接声明。这就是为什么你也需要内部的extern

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

(作为旁注,我将i.h也包括在i.cpp中,这样我就不必在实现中记住与extern "C"混淆了。)

问题是constextern相互交战。const意味着(除其他事项外),"使此定义成为内部的,除非在其上有显式的extern。"当定义在extern "C"块中时,没有extern 直接在定义上,因此来自const的"隐式内部"优先。其他定义都直接在定义上有一个extern,所以它变成了外部的。

int ID可以和不可以这样定义:

小心!extern "C"在不同的上下文中有不同的效果。

N3797§7.5/7:

直接包含在链接规范中的声明将被处理就好像它包含extern说明符(7.1.1)用于确定声明的名称的链接以及它是否为定义。这样的声明不能指定存储类。

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

所以你的代码片段中的第二行只是一个声明,而你的第三行也是一个定义。这改变了链接规范对声明的影响-您不能给出在c++翻译单元C链接中定义的名称。