Какие проблемы можно ожидать при компиляции кода C с помощью компилятора C ++? - PullRequest
33 голосов
/ 14 мая 2009

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

Если я не заверну все свои файлы C в extern C { ... }, я получу искажение имени там, где я меньше всего этого ожидаю? Есть ли какая-то причина, почему я действительно не должен этого делать?

Для фона у нас есть очень большая кодовая база, написанная на C. В течение нескольких лет мы прыгали через обручи, чтобы делать вещи, которые естественным образом приходят через C ++ (например, наследование homebrewe). Мы хотели бы начать двигаться к C ++, но постепенно. получение нашей CORBA-подобной платформы для ее поддержки и рефакторинг модулей по мере использования более естественного подхода, который мог бы предоставить C ++.

Ответы [ 8 ]

33 голосов
/ 14 мая 2009

Я однажды сделал что-то подобное. Основным источником проблем было то, что C ++, как вы и предполагали, более строг в отношении типов. Вам нужно будет добавить приведение, где void * смешивается с указателями других типов. Как выделение памяти:

Foo *foo;
foo = malloc(sizeof(*foo));

Выше приведен типичный код C, но для него потребуется приведение в C ++:

Foo *foo;
foo = (Foo*)malloc(sizeof(*foo));

В С ++ появились новые зарезервированные слова, такие как "класс", "и", "bool", "catch", "delete", "явный", "изменяемый", "пространство имен", "новый", " оператор "," или "," private "," protected "," friend "и т. д. Их нельзя использовать, например, в качестве имен переменных.

Выше, вероятно, наиболее распространенные проблемы, когда вы компилируете старый код C с помощью компилятора C ++. Полный список несовместимостей см. В Несовместимости между ISO C и ISO C ++ .

.

Вы также спрашиваете об искажении имени. В отсутствие внешних оболочек "C" компилятор C ++ будет манипулировать символами. Это не проблема, если вы используете only компилятор C ++ и не используете dlsym () или что-то подобное для извлечения символов из библиотек.

21 голосов
/ 14 мая 2009

См. Несовместимости между ISO C и ISO C ++ для очень подробного списка всех несовместимостей. Есть много тонких проблем, в том числе некоторые, которые не сразу проявляются в ошибке компилятора. Например, одной из проблем, которая может быть проблемой, является размер символьных констант:

// In C, prints 4.  In C++, prints 1
printf("%d\n", sizeof('A'));
8 голосов
/ 14 мая 2009

Если я не заверну все свои файлы C в "extern C {...}", я получу искажение имени там, где я меньше всего этого ожидаю?

Это кусает вас, когда вы пытаетесь соединить C и C ++.

Я написал много заголовочных файлов, содержащих:

#ifdef __cplusplus
    extern "C" {
#endif

// rest of file

#ifdef __cplusplus
    }
#endif

Через некоторое время он сливается с существующим множественным включенным шаблоном, и вы перестаете его видеть. Но вы должны быть осторожны в том месте, где вы его поместили - обычно он принадлежит после , который включает любой заголовок.

Есть ли какая-то причина, почему я действительно не должен этого делать?

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

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

3 голосов
/ 16 декабря 2015

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

Я успешно скомпилировал и использовал следующие C-библиотеки с открытым исходным кодом как C ++:

  • XML-парсер Expat
  • растеризатор шрифтов FreeType2
  • libjpeg: обрабатывает изображения JPEG
  • libpng: обрабатывает изображения PNG
  • библиотека сжатия Zlib

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

Почему я это сделал? Потому что я продаю коммерческую библиотеку, которую люди связывали прямо в своих приложениях; и иногда их приложения были связаны с другими версиями Expat, FreeType и т. д. Это вызывало ошибки с множественными символами. Самое чистое, что нужно было сделать, это переместить все в мою библиотеку и спрятать это в моем пространстве имен.

Однако я не делал этого со всеми библиотеками с открытым исходным кодом, которые я использую. Некоторые из них еще не вызывали конфликтов, и я так и не решил их исправить, что без проблем довольно утомительно. Интересным исключением является SQLite, который я не смог собрать в C ++. Поэтому я провел массивный поиск и замену, добавив префикс (название моего продукта) к каждому внешне видимому символу. Это решило проблему моего клиента.

3 голосов
/ 14 мая 2009

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

2 голосов
/ 21 мая 2014

Я делал это до использования MSVC, если вы используете MSVC, хорошая стратегия:

  1. Установите отдельные файлы для построения в виде CPP, чтобы вы могли постепенно переходить к компилятору CPP.
  2. Работайте по файлам, используя Ctrl + F7 только для создания этого файла.
  3. Вместо того, чтобы приводить все malloc, вы можете вместо этого создать шаблонную версию

foo = (Foo *) malloc (sizeof (* foo));

становится

foo = malloc<Foo>();

И, конечно, вы можете иметь перегрузку для случаев, когда вы хотите Foo + n байтов

Я бы также рекомендовал переключать выделения памяти для использования RAII, где это возможно, и я обнаружил, что некоторые функции, которые довольно сложны, поэтому переключение на RAII было слишком высоким риском, для большинства случаев это было достаточно просто сделать.

1 голос
/ 14 мая 2009

C ++ имеет более строгую проверку типов, поэтому вам может понадобиться добавлять приведение к каждому вызову malloc / realloc / calloc.

0 голосов
/ 19 апреля 2016

попробуйте скомпилировать с помощью компилятора C ++:

typedef enum{ false = 0, true = 1} bool;
...