У меня есть библиотека 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
. Здесь я хочу использовать вместо этого исходный файл C ++ main.cpp
и скомпилировать / связать его с g++
.
Во время компиляции исходного файла C ++ возникли следующие три проблемы:
- один из файлов заголовков библиотеки C содержит зарезервированное слово C ++
new
(это имя целого числа), что привело к фатальной ошибке; и - один из файлов заголовков библиотеки C содержит вызов
calloc
(отсутствует явное приведение типа), что привело к фатальной ошибке; и - различные файлы библиотеки C содержат код, в котором происходит сравнение знаковых и беззнаковых целых чисел, что приводит к предупреждению.
Изменить: я попытался использовать "трюк" #extern "C" { #include "obsolete_c_library.h" }
, как предлагалось в комментариях, но это не решило ни одной из моих проблем.
Я могу решить проблему 1, переименовав все экземпляры зарезервированных слов и заменив их - в основном - чем-то еще. Я могу решить проблему 2, указав тип вызова calloc
. Я мог бы попытаться отсортировать предупреждения по предложенным здесь идеям: Как отключить предупреждения GCC для нескольких строк кода.
Но я все еще задаюсь вопросом, есть ли способ преодолеть эти трудности элегантным высокоуровневым способом, без фактического воздействия на исходную библиотеку?
Соответствующие: Где C не является подмножеством C ++? и Могу ли я привести результат malloc? и Как использовать extern для обмена переменными между исходными файлами ?.
2 ответа
Вообще говоря, небезопасно добавлять файлы заголовков C #include
в исходные тексты C ++, если эти заголовки не были созданы в ожидании такого использования. В некоторых случаях его можно заставить работать, но вы должны быть готовы либо изменить заголовки, либо написать свои собственные объявления для функций и глобальных переменных, к которым вы хотите получить доступ.
Как минимум, если заголовки C объявляют какие-либо функции, и вы не перекомпилируете эти функции в C ++, вы должны убедиться, что объявлениям назначена связь C в вашем коде C ++. Заголовки C нередко учитывают это автоматически с помощью директив условной компиляции, но если они этого не делают, вы можете сделать это с другой стороны, заключив включение (я) в блок связывания C:
extern "C" {
#include "myclib.h"
}
Если заголовки C объявляют глобальные объекты, имена которых конфликтуют с ключевыми словами C ++, и на которые не нужно ссылаться , тогда вы можете использовать препроцессор, чтобы переопределить их:
#define new extern_new
#include "myclib.h"
#undef new
Это не обязательно сработает, но попробовать стоит. Не забудьте #undef
такие макросы после включения заголовков C, как показано.
Могут быть и другие забавные трюки, которые вы можете использовать с макросами для адаптации определенных заголовков к C ++, но в какой-то момент имеет смысл просто скопировать / переписать необходимые объявления (и только те) либо в вашем основном источнике C ++, либо в вашем собственном Заголовок C ++. Обратите внимание, что это не устраняет необходимость объявлять связь C - это требование исходит из того, что библиотека была скомпилирована компилятором C, а не компилятором C ++.
Вы можете написать дубликат заголовка c, с той лишь разницей, что не будет декларации
extern int new
. Затем используйте только что созданный дружественный к C ++ заголовок вместо старого несовместимого.Если вам нужно ссылаться на эту переменную из C ++, вам нужно сделать что-то более сложное. Вам нужно будет написать новую библиотеку-оболочку на c, которая предоставляет
функции чтения и записиуказатель на c ++, который можно использовать для доступа к неудачно названной переменной.Если некоторые встроенные функции ссылаются на переменную, вы можете исключить их из повторяющегося заголовка и, если вам нужно вызвать их из C ++, повторно реализовать их в удобной для C ++ манере. Только не давайте повторной реализации то же имя в
extern "C"
, потому что это может привести к конфликту с исходной встроенной функцией, которая, возможно, используется некоторым существующим кодом c.Выполните такое же дублирование заголовка, как описано в 1., исключив проблемную встроенную функцию и повторно реализовав ее при необходимости.
Предупреждения можно игнорировать или отключить, как вы уже знаете. Нет необходимости изменять исходные заголовки. Вы можете переписать любые {const, type} -unsafe встроенные функции с версиями, которые не генерируют предупреждения, но вы должны учитывать, стоит ли ваше время того.
Недостатком этого подхода является то, что теперь у вас есть две версии некоторых / всех заголовков. Новые, используемые c ++, и старые, которые могут использоваться некоторым старым кодом.
Если вы можете отказаться от требования не касаться исходной библиотеки и вам не нужно работать с существующим скомпилированным двоичным файлом, тогда элегантным решением будет просто переименовать проблемные переменные (1.). Сделайте несовместимые с C ++ встроенные функции (2.) не встроенными и переместите их в исходные файлы C. Исправьте небезопасный код (3.), который генерирует предупреждения, или, если предупреждение специфично для C ++, просто сделайте функцию не встроенной.
Похожие вопросы
Связанные вопросы
Новые вопросы
c++
C++ — это язык программирования общего назначения. Изначально он разрабатывался как расширение C и имел аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде, который будет скомпилирован с помощью компилятора C++. Используйте тег версии для вопросов, связанных с конкретной стандартной версией [C++11], [C++14], [C++17], [C++20] или [C++23]. и т.д.