为什么要在C++命名空间周围使用extern "C"?

13

几天前,我遇到了这段 C++ 代码,虽然我不能贴出代码本身,但我可以用一些示例代码重现问题。 首先是文件 namespace.h:

#include <iostream>
using namespace std;

namespace useless{
  class X {
     int m_myint;
     static X *m_foobar;
     X* getPrivVal(void);
  public:
     int getMember(void);
     X* getStaticVal(void);
  };
}

接下来是namespace.cpp

#include "namespace.h"

extern "C"{
   namespace useless{
     X* X::m_foobar = NULL;
     X* X::getPrivVal(void){
         if(m_foobar == NULL)
             m_foobar = new X;
         return(m_foobar);
     }
   }
}

namespace useless {
   int X::getMember(void){
       if(m_myint == 0)
           m_myint = 1;
      return(m_myint);
   }
   X* X::getStaticVal(void){
        return(getPrivVal());
   }
}

using namespace useless;

int main(void){
    X y;
    cout << "The int value is " << y.getMember() << endl;
    cout << "The value of the static member is " << y.getStaticVal() << endl;
    return(0);
}

当我使用g++ 3.4.3时,这段代码编译和链接都很好,但是当我使用g++ 4.x时,它会出现以下错误。我已经尝试过GCC 4.6.1和GCC 4.2.1。在Linux和Mac上都尝试过,结果相同。

这是错误信息(Suse):

g++ -o namespace namespace.cpp
namespace.h:8:15: error: previous declaration of useless::X* 
    useless::X::m_foobar with C++ linkage
namespace.cpp:5:11: error: conflicts with new declaration with C linkage

请问有谁能解释一下这个传统的C++代码想要做什么,这可能是一个黑客或绕过我不再了解的老问题的解决方法。哦,顺便说一句,在extern "C"内部的方法由C++代码调用,而不是我最初怀疑的任何C代码调用。 提醒您,这是遗留代码,可能是在2001/2002年编写的。


谢谢大家。我已经去掉了extern "C",没有太大的影响。 @Bjorn Pollex: 编写该代码的人早已离开。


6
如果这段代码有版本控制,检查历史记录找到谁写的,然后用棍子打他们,直到他们忏悔他们的罪孽为止。 - Björn Pollex
3个回答

14
extern "C" 指令有两个作用,它可以在可能的情况下禁用名称修饰并使用 C 调用约定。 在这种特殊情况下,由于中间存在命名空间,不能禁用名称修饰,因此可以添加该指令来强制使用特定的调用约定。
实际上,代码有误,因为声明未强制要求使用 extern "C",而定义却使用了,这是不正确的。如果编译器按照所示指令进行操作,则调用者将使用 C++ 命名和调用约定,而函数将使用 C 变体,如果两者不同,则结果将产生未定义的行为。

6
看起来这是一种尝试在不使用C++名称重整的情况下生成变量的方法。这是使用extern "C"的一部分。
显然,较新的编译器意识到这并不能真正地奏效。

2
如果您有一段想从另一种语言(如C、FORTRAN等)编写的模块中调用的C++代码,您需要关闭C++名称修饰。
编辑: 真正奇怪的是,他们在定义时这样做,但在声明时不这样做。令人惊讶的是它居然编译通过了。

3
如果讨论C++专属的特性,比如类和命名空间,关闭名称混淆就没有意义。 - Lily Ballard

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