Зачем использовать extern "C" вокруг пространства имен C ++ - PullRequest
13 голосов
/ 10 октября 2011

Несколько дней назад я наткнулся на этот кусок кода 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 годов.


Спасибо, ребята. Я пошел вперед и избавился от внешнего «С» без какого-либо серьезного воздействия. @ Бьорн Поллекс: парень, который написал этот код, давно ушел.

Ответы [ 3 ]

14 голосов
/ 10 октября 2011

Директива extern "C" имеет два эффекта: она отключает искажение, когда это возможно, и использует соглашение о вызовах C. В этом конкретном случае, поскольку между ними существует пространство имен, искажение имен нельзя отключить, поэтому его можно было бы добавить для принудительного выполнения определенного соглашения о вызовах.

Код на самом деле неверен в том смысле, что объявление не заставляет extern "C", но определение делает, что неверно. Учтите, что если бы компилятор просто следовал директиве, как показано, вызывающая сторона использовала бы соглашения об именовании и вызовах C ++, тогда как функция использовала бы вариант C, если они различаются, результатом будет неопределенное поведение.

6 голосов
/ 10 октября 2011

Похоже на попытку сгенерировать переменные без искажения имени в C ++. Это одна часть использования extern "C".

Более новый компилятор, очевидно, понимает, что он действительно не работает.

2 голосов
/ 10 октября 2011

Если у вас есть фрагмент кода C ++, который вы хотите вызвать из модуля, написанного на другом языке (C, FORTRAN или любой другой), вы хотите отключить искажение имени C ++.

Edit: Действительно странная вещь в том, что они сделали это по определению, но не по объявлению. Удивительно, что он когда-либо компилируется

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...