Подтвердить что ты не робот

Как связать старый код C с зарезервированными ключевыми словами в нем с С++?

У меня есть 10-летняя библиотека C, которая, я считаю, использовалась для прекрасных работ в старые добрые времена, но когда я попытался использовать ее с источником С++ (содержащим основную функцию) на днях Я столкнулся с некоторыми трудностями.

Изменить: для пояснения, библиотека C компилируется только с помощью gcc, и она генерирует объектный файл old_c_library.o. Предполагалось, что эта библиотека будет использоваться таким образом, чтобы заголовочный файл C old_c_library.h был #include d в исходном файле main.c C. Затем ваш основной исходный файл C должен быть скомпилирован и связан с old_c_library.o через gcc. Здесь я хочу вместо этого использовать исходный файл С++ main.cpp и компилировать/связывать его с g++.

При компиляции исходного файла С++ возникли следующие три проблемы:

  • один из файлов заголовков библиотеки C содержит зарезервированное слово С++ new (это имя целого), что привело к фатальной ошибке; и
  • один из файлов заголовков библиотеки C содержит вызов calloc (явно не указан тип), что привело к фатальной ошибке; и
  • В различных файлах библиотеки C содержится код, в котором происходит сравнение целых чисел с подписью и без знака, что привело к предупреждениям.

Изменить: я попытался использовать трюк #extern "C" { #include "obsolete_c_library.h" }, как это было предложено в комментариях, но это не решило ни одной из моих проблем.

Я могу разобраться в проблеме 1, переименовав все экземпляры зарезервированных слов и заменив их - в основном - что угодно. Я могу решить проблему 2, указав вызов calloc. Я могу попытаться разобраться с предупреждениями, предложенными здесь: Как отключить предупреждения GCC для нескольких строк кода.

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


Соответствующие: Где C не подмножество С++? и Я делаю результат malloc? и Как использовать extern для обмена переменными между исходными файлами?.

4b9b3361

Ответ 1

Вообще говоря, заголовки #include C в файлы С++ небезопасны, если эти заголовки не были созданы в ожидании такого использования. В некоторых случаях его можно заставить работать, но вы должны быть готовы либо изменить заголовки, либо написать свои собственные объявления для функций и глобальных переменных, к которым вы хотите получить доступ.

Как минимум, если заголовки C объявляют какие-либо функции, и вы не перекомпилируете эти функции в С++, вы должны убедиться, что объявлениям присваивается ссылка C в вашем коде на С++. Это не редкость для заголовков C, которые автоматически учитываются с помощью условных компиляционных директив, но если они этого не делают, вы можете сделать это с другой стороны, обернув включение (и) в блок C-ссылок:

extern "C" {
#include "myclib.h"
}

Если заголовки C объявляют глобальные переменные, имена которых конфликтуют с ключевыми словами С++ и которые вам не нужно ссылаться, вы можете использовать препроцессор для их переопределения:

#define new extern_new
#include "myclib.h"
#undef  new

Это не гарантировало работу, но стоит попробовать. Не забывайте #undef такие макросы после включения заголовков C., как показано.

Могут быть другие забавные трюки, которые вы можете играть с макросами для адаптации определенных заголовков к С++, но в какой-то момент имеет смысл просто копировать/переписывать необходимые объявления (и только те), либо в ваш основной источник С++, либо в вашем собственном заголовке С++. Обратите внимание, что это не устраняет необходимость объявления C-ссылки - это требование возникает из библиотеки, скомпилированной компилятором C, а не компилятором С++.

Ответ 2

  • Вы можете написать дубликат заголовка c, с той лишь разницей, что отсутствует объявление extern int new. Затем используйте вновь созданный дружественный заголовок С++ вместо старого, несовместимого.

    Если вам нужно передать эту переменную из С++, вам нужно сделать что-то более сложное. Вам нужно будет написать новую библиотеку-оболочку в c, которая предоставляет функции чтения и записи указатель на С++, который можно использовать для доступа к к сожалению названной переменной.

    Если некоторые встроенные функции относятся к переменной, вы можете оставить их из дублированного заголовка, и если вам нужно вызвать их из С++, повторите их реализацию в дружественном режиме С++. Просто не давайте повторное имя с тем же именем в extern "C", потому что это даст вам конфликт с исходной встроенной функцией, возможно, используемой некоторым существующим c-кодом.

  • Сделайте то же самое дублирование заголовка, как описано в 1. оставляя проблемную встроенную функцию и при необходимости повторно реализуя.

  • Предупреждения можно игнорировать или отключать, как вы уже знаете. Не нужно изменять исходные заголовки. Вы можете переписать любые функции {const, type} -unsafe inline с версиями, которые не генерируют предупреждения, но вам нужно подумать о том, стоит ли вам это время.

Недостатком такого подхода является то, что теперь у вас есть два раздела некоторых/всех заголовков. Новые, используемые С++, и старые, которые могут использоваться каким-то старым кодом.


Если вы можете отказаться от требования не касаться исходной библиотеки и не нуждаться в работе с существующим скомпилированным двоичным кодом, то элегантным решением было бы просто переименовать проблематичные переменные (1.). Внесите не-С++-совместимые встроенные функции (2.) non-inline и переместите их в исходные файлы c. Исправьте небезопасный код (3.), который генерирует предупреждения или если предупреждение является С++ конкретным, просто сделайте функцию не встроенной.