#c #c #gcc
#c #c #gcc
Вопрос:
Несколько дней назад я наткнулся на этот фрагмент кода 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 годах.
Спасибо, ребята. Я пошел дальше и избавился от внешнего «C» без каких-либо серьезных последствий. @Бьорн Поллекс : Парень, который написал этот код, давно ушел.
Комментарии:
1. Если этот код контролируется версиями, проверьте историю, чтобы найти того, кто это написал, и бейте их палкой, пока они не покаются в своих грехах.
Ответ №1:
extern "C"
Директива имеет два эффекта: она отключает искажение, когда это возможно, и использует соглашение о вызовах C. В данном конкретном случае, поскольку между ними существует пространство имен, искажение имен нельзя отключить, поэтому его можно было бы добавить для принудительного выполнения определенного соглашения о вызовах.
Код на самом деле неверен в том смысле, что объявление не выполняет принудительное extern "C"
действие, а определение выполняет, что неверно. Учтите, что если компилятор просто следовал директиве, как показано, вызывающий объект будет использовать соглашения об именовании и вызовах C , в то время как функция будет использовать вариант C, если они отличаются, результатом будет неопределенное поведение.
Ответ №2:
Похоже на попытку сгенерировать переменные без искажения имен C . Это одна из частей использования extern "C"
.
Новый компилятор, очевидно, понимает, что это действительно не работает.
Ответ №3:
Если у вас есть фрагмент кода C , который вы хотите вызвать из модуля, написанного на другом языке (C, FORTRAN или любом другом), вы хотите отключить искажение имен C .
Редактировать: действительно странно то, что они сделали это в определении, но не в объявлении. Удивительно, что он когда-либо компилировался
Комментарии:
1. Отключение искажения имен не имеет смысла, когда вы говорите об эксклюзивных функциях C , таких как классы и пространства имен.