Программа C++, использующая заголовки библиотеки C, распознает это как ключевое слово. Внешняя ошибка C?

Моя программа на C++ должна использовать внешнюю библиотеку C. Поэтому я использую

extern "C"
{
   #include <library_header.h>
}

синтаксис для каждого модуля, который мне нужно использовать.

Это работало нормально до сих пор. Модуль использует имя this для некоторых переменных в одном из своих заголовочных файлов. Сама библиотека C компилируется нормально, потому что, насколько мне известно, this никогда не было ключевым словом в C.

Но, несмотря на то, что я использую синтаксис extern "C", я получаю ошибки из своей программы на C++, когда включаю этот заголовочный файл.

Если я переименую каждый элемент this в этом заголовочном файле библиотеки C во что-то вроде _this, все будет работать нормально.

Вопрос в том:

Разве синтаксиса extern "C" не должно быть достаточно для обратной совместимости, по крайней мере на уровне синтаксиса, для файла заголовка? Это проблема с компилятором?


person nyarlathotep108    schedule 03.09.2014    source источник
comment
Все, что делает extern "C", — это говорит компилятору не выполнять изменение имени.   -  person Some programmer dude    schedule 03.09.2014
comment
stackoverflow.com/q/1041866/1147772   -  person Drax    schedule 03.09.2014
comment
@JoachimPileborg - extern "C" говорит использовать изменение имени C, что обычно означает добавление подчеркивания.   -  person Pete Becker    schedule 03.09.2014
comment
extern "C" не волшебным образом переключает текущий язык на C. Все, что он влияет, это спецификация компоновки внешних объектов. Ваш заголовочный файл по-прежнему скомпилирован как код C++ и должен подчиняться всем правилам языка C++.   -  person AnT    schedule 03.09.2014


Ответы (4)


Разве синтаксиса extern «C» не должно быть достаточно для обратной совместимости, по крайней мере, на уровне синтаксиса, для файла заголовка? Это проблема с компилятором?

Нет. Extern "C" предназначен для связывания - в частности, политики, используемой для сгенерированных имен символов ("изменение имен"), и соглашения о вызовах (какая сборка будет сгенерирована для вызова API и значений параметров стека), а не для компиляции.

Ваша проблема не ограничивается ключевым словом this. В нашей текущей кодовой базе мы переносим некоторый код на C++, и у нас есть такие конструкции:

struct Something {
    char *value;
    char class[20]; // <-- bad bad code!
};

Это прекрасно работает в коде C, но (как и вы) мы вынуждены переименовывать, чтобы компилировать как C++.

person utnapistim    schedule 03.09.2014
comment
Совет: при написании библиотек C пишите код, совместимый с именами C++. Сохраняет много головной боли для других разработчиков. - person Cole Johnson; 03.09.2014
comment
RE: ваша проблема с классом, обратите внимание на хакерский обходной путь, поддерживаемый вашим компилятором, в моем ответе. Конечно, не делай этого, исправь! :-) - person HostileFork says dont trust SE; 03.09.2014
comment
Хорошо, теперь это совершенно ясно. Как вы сказали, проблема с ключевым словом this была решена с помощью переименования, она начала жаловаться на преобразования int/bool и другие основные отличия основного языка C/C++. Я думал, что поскольку это extern C, он будет компилироваться с использованием спецификаций C, и я был совершенно неправ. Спасибо! - person nyarlathotep108; 03.09.2014
comment
@ColeJohnson: Обычно это хороший совет для заголовков, плохой совет для реализации. Вы хочете, чтобы код C ломался быстро и сильно ломался, если кто-то попытается скомпилировать его с помощью компилятора C++. Внесение незаметных ошибок из-за того, что это разные языки с разной семантикой, гораздо хуже. - person R.. GitHub STOP HELPING ICE; 03.09.2014
comment
@R.. Ты прав. Я ссылался на заголовки. Я просто подумал, что это подразумевается; думаю нет. Реализация - это совсем другое, согласен. - person Cole Johnson; 03.09.2014
comment
@R.. Э... Я согласен с вашей общей точкой зрения, что если есть какая-то серая область совместимости, вы должны попытаться устранить ее как можно быстрее и вслух при перекомпиляции. Но это не имеет ничего общего с тем, что программисты на C активно называют поля структур class и глобальные переменные this. - person HostileFork says dont trust SE; 04.09.2014

Как ни странно, многие компиляторы не запрещают принудительно переопределение ключевого слова через препроцессор:

#include <iostream>

// temporary redefinition to compile code abusing the "this" keyword
#define cppThis this
#define this thisFunction

int this() {
    return 1020;
}

int that() {
   return this();
}

// put the C++ definition back so you can use it
#undef this
#define this cppThis

struct DumpThat {
    int dump() {
       std::cout << that();
    }
    DumpThat() {
       this->dump();
    }
};

int main ()
{
    DumpThat dt;
}

Так что, если вы упираетесь в стену, это может позволить вам скомпилировать файл, написанный на предположениях C, которые вы не можете изменить.

Однако это не позволит вам получить имя компоновщика "this". Могут быть компоновщики, которые позволяют вам выполнять какое-то переназначение имен, чтобы избежать коллизий. Побочным эффектом этого может быть то, что они позволяют вам сказать thisFunction -> this и не иметь проблем с тем, что правая часть сопоставления является ключевым словом.

В любом случае... лучший ответ, если вы можете это изменить, это... изменить это!

person HostileFork says dont trust SE    schedule 03.09.2014
comment
Я не думаю, что это странно или что у компилятора есть выбор. Шаг препроцессора определяется на уровне токена. На этом этапе токены еще не были преобразованы в ключевые слова, поэтому вы не можете использовать токены с ключевыми словами иначе, чем токены без ключевых слов. - person MSalters; 03.09.2014
comment
@MSalters См. Переопределение ключевых слов в C/C++... можно, конечно, занести в черный список слова из-за использования препроцессора. - person HostileFork says dont trust SE; 03.09.2014
comment
Ой, верно - C запрещает это только на этапе 7/8, после предварительной обработки на этапе 4 (см. ответ md5), но в C++ это запрещено полностью (согласно связанному вопросу). Но this в любом случае не будет ключевым словом в C. Поэтому вместо того, чтобы условно переопределять его для C++, вы должны условно переопределить его для C. - person MSalters; 03.09.2014
comment
Это хорошее решение, которое может решить общую проблему с ключевыми словами, но на самом деле оно не решит в целом всех различий C/C++. Думаю, это хорошо, что мы можем редактировать заголовочные файлы, в том числе из внешних библиотек. - person nyarlathotep108; 04.09.2014

Если бы extern "C" позволял использовать ключевые слова C++ в качестве символов, компилятору пришлось бы каким-то образом разрешать их за пределами разделов extern "C". Например:

extern "C" {
    int * this;  //global variable
    typedef int class;
}


int MyClass::MyFunction() { return *this; }  //what does this mean?
                                             //MyClass could have a cast operator
class MyOtherClass;  //forward declaration or a typedef'ed int?
person IronMensan    schedule 03.09.2014

Не могли бы вы более подробно рассказать об «использовании этого имени для некоторых переменных в одном из его заголовочных файлов»?

Это действительно переменная или это параметр в прототипе функции?

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

#ifdef __cplusplus
  extern "C" {
   void aFunc(int);
  }
#else
 void aFunc(int this);
#endif

Помните, что в файлах заголовков нет ничего волшебного — они просто предоставляют код, который лексически включается в точку #include — как если бы вы их скопировали и вставили.

Таким образом, вы можете иметь свою собственную копию заголовка библиотеки, которая выполняет трюки, подобные описанным выше, просто становясь проблемой обслуживания, чтобы гарантировать, что вы отслеживаете, что происходит в исходном заголовке. Если это может стать проблемой, добавьте скрипт в качестве шага сборки, который запускает сравнение с оригиналом и гарантирует, что единственным отличием является ваш код обходного пути.

person Andy Dent    schedule 03.09.2014