【问题标题】:Extern used twice in C++Extern 在 C++ 中使用了两次
【发布时间】:2020-08-11 12:03:08
【问题描述】:

我很好奇在链接过程中会发生什么,并且在我研究这个领域的过程中,我发现了这段代码

#ifdef __cplusplus
extern “C” { 
#endif

extern double reciprocal (int i);

#ifdef __cplusplus
}
#endif

代码在某个头文件中,该头文件被一个程序的 .c 和 .cpp 源文件包含。它是一个函数的声明,然后在 .cpp 文件中定义。为什么它起作用?我的意思是,在 .cpp 文件的编译过程中,这将变成

extern "C" {
    extern double reciprocal (int i);
}

外部 extern 既使函数在全局范围内可见,又将 C++ 风格的函数名转换为 C 风格。但也有内在的外在。函数externed两次可以吗?

【问题讨论】:

  • 忽略预处理#ifdefs,只看第二个sn-p,前者是语言链接,在你写的时候,主要的意图 将其中的一些实体(函数类型,以及具有外部链接和变量的函数名称和变量)与 C 语言链接,具有这些实体不会具有的一个主要效果错位的名称,而且将被放置在全局命名空间中(因为在 C ABI 中没有命名空间)。 ...
  • ... 内部extern 不是语言链接说明符而是存储类说明符,不会影响两者的协同,因为reciprocal 已经有外部链接即使没有extern(这反过来意味着它具有语言链接,使其可能链接翻译单元来自其他语言)。

标签: c++ extern extern-c


【解决方案1】:

c++ 语言对添加新关键字很敏感,因此有些关键字会被重用以表示不同的意思。 extern 是这些重复使用的关键字之一。它有3 possible meanings:

  1. 外部链接 - 变量或函数在其他地方定义
  2. 语言链接 - 变量或函数以“外部”语言定义
  3. 显式模板实例化声明

在您的情况下,您使用的是 1 和 2。extern "C" 声明代码具有 "C" 而不是默认的 "C++" 链接。这也意味着外部链接,因此在纯 C++ 代码中您可以编写:

extern "C" {
    double reciprocal (int i);
}

reciprocal 将自动标记为extern。添加额外的extern 无效,并且对于没有extern "C" 包装器的C 版本是必需的。

请注意,如果您使用extern "C" 的单一声明版本,则使用第二个extern 无效:

extern "C" extern double reciprocal (int i);

由于不需要第二个extern,因此正确的声明是:

extern "C" double reciprocal (int i);

【讨论】:

  • "[...] 和倒数将自动标记为extern" - 我不认为这是准确的,什么会“标记为extern”甚至在这种情况下意味着,因为我们刚刚确定 extern 关键字在 C++ 中严重过载?语言链接块仅将 C 语言链接应用于例如由其大括号块包含的函数名称具有外部链接 - 它不会自动将其标记为extern。从某种意义上说,对于这样的名字,相当于用extern "C"标记名字。
  • 作为一个(人为的)练习,我们甚至可以将reciprocal 声明为static,之后extern "C" 块将对该特定函数名称没有影响,因为它不再具有外部链接.
  • @dfri 是的,您甚至不需要将其标记为静态,函数的 extern "C" 声明必须是第一个声明:“函数可以在没有链接的情况下重新声明用语言规范声明后,第二个声明将重用第一个语言链接。反之则不然:如果第一个声明没有语言链接,则假定为“C++”,用另一种语言重新声明是错误的. ": godbolt.org/z/AeQUgu
  • 我的示例应用于extern "C" { declaration-seq(optional) },它本身不是声明,而是应用语言链接。如果例如declaration-seq 中的函数声明之一由static 标记,extern "C" { ... } 块不会对其应用 C 语言链接。我相信您的内容涵盖了extern "C" { ... } 块内声明的重新声明超出,或者使用声明语言链接表单extern "C" declaration 时。
  • gcc 在这里仍然应用 c 链接:godbolt.org/z/EXcTH8
猜你喜欢
  • 1970-01-01
  • 2021-07-15
  • 1970-01-01
  • 2012-05-12
  • 1970-01-01
  • 1970-01-01
  • 2019-12-22
  • 2012-11-20
  • 1970-01-01
相关资源
最近更新 更多