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

Преобразование источника C в С++

Как вы собираетесь конвертировать достаточно большой ( > 300K), довольно зрелый C-код C в С++?

Тип CI имеет в виду разделение на файлы, грубо соответствующие модулям (т.е. менее гранулированные, чем типичная декомпозиция на основе OO), используя внутреннюю связь вместо частных функций и данных и внешнюю привязку для публичных функций и данных, Глобальные переменные широко используются для связи между модулями. Доступен очень обширный набор тестов интеграции, но нет тестов уровня (то есть модуля).

Я имею в виду общую стратегию:

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

Очевидно, это будет довольно много работы. Есть ли какие-либо тематические исследования/военные истории в этом переводе? Альтернативные стратегии? Другие полезные советы?

Примечание 1: программа является компилятором, и, вероятно, миллионы других программ полагаются на то, что ее поведение не меняется, поэтому опциональное переписывание в значительной степени не является вариантом.

Примечание 2: источнику почти 20 лет, и, возможно, 30% отторжения кода (строки, измененные + добавленные/предыдущие общие строки) в год. Другими словами, он поддерживается и расширяется. Таким образом, одна из целей будет заключаться в увеличении удобства обслуживания.

[Ради вопроса, предположим, что перевод в С++ является обязательным, а его оставление на C - не. Пункт добавления этого условия состоит в том, чтобы отсеять ответы "оставьте его в C".]

4b9b3361

Ответ 1

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

Насколько это возможно, разделите его на этапы, которые можно выполнить с минимальными эффектами на другие части. Построение фасадной системы, как предположил Федерико Рампони, является хорошим началом - когда все имеет фасад С++ и общается через него, вы можете изменить внутренности модулей с уверенностью, что они не могут повлиять на что-либо вне их.

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

Переключение еще не завершено - мы временно приостановили участие в промежуточных выпусках (мы стремимся к выпуску в виде постов каждые несколько недель), но это хорошо по пути, и ни один клиент не жаловался на какие-либо проблемы, Наши люди QA нашли только одну проблему, о которой я тоже помню.: -)

Ответ 2

Как насчет:

  • Скомпилировать все в подмножестве С++ C и получить эту работу, а
  • Внедрение набора фасадов, оставив код C неизменным?

Почему "перевод на С++ обязательно"? Вы можете обернуть код C без боли, превратив его в огромные классы и т.д.

Ответ 3

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

Основная идея - обозначить группы данных как классы, а затем получить инструмент для реорганизации кода для перемещения этих данных в классы, перемещать функции только на эти данные в эти классы, и пересмотреть все обращения к этим данным на вызовы классов.

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

Инструментом, способным выполнять эту задачу, является наш DMS Software Reengineering Инструментарий. DMS имеет сильные синтаксические анализаторы C для чтения вашего кода, захватывает код C как абстрактные синтаксические деревья компилятора (и в отличие от обычного компилятора) может вычислять анализы потока во всем 300K SLOC. DMS имеет переднюю панель С++, которая может использоваться как "обратный" конец; один пишет преобразования, которые сопоставляют синтаксис C с синтаксисом С++.

Основная задача реинжиниринга С++ на большой системе авионики дает некоторое представление о том, как использовать DMS для такого вида деятельности. См. Технические документы на www.semdesigns.com/Products/DMS/DMSToolkit.html, конкретно Реконструкция моделей компонентов С++ с помощью автоматической трансформации программ

Этот процесс не для слабонервных. Но чем кто-либо который рассмотрит ручную рефакторинг большого приложения уже не боится тяжелой работы.

Да, я связан с компанией, будучи ее главным архитектором.

Ответ 4

Я бы написал классы С++ по интерфейсу C. Не прикасаясь к коду C, вы снижаете вероятность взлома и ускорения процесса.

Как только у вас будет интерфейс С++; то это тривиальная задача копирования + вставки кода в ваши классы. Как вы упомянули - на этом этапе очень важно выполнить модульное тестирование.

Ответ 5

В настоящее время GCC находится в середине перехода к С++ с C. Они начали, перемещая все в общее подмножество C и С++, очевидно. Как они это сделали, они добавили предупреждения GCC для всего, что они нашли, найденные под -Wc++-compat. Это должно привести вас к первой части вашего путешествия.

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

Ответ 6

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

Ответ 7

Бросьте еще одну глупую идею:

  • Скомпилируйте все в подмножестве С++ C и получите эту работу.
  • Начните с модуля, преобразуйте его в огромный класс, затем в экземпляр и создайте интерфейс C (идентичный тому, с которого вы начали) из этого экземпляра. Пусть оставшийся код C работает с этим интерфейсом C.
  • Рефакторинг по мере необходимости, увеличивая подсистему OO из кода C один модуль за раз и отбрасывая части интерфейса C, когда они становятся бесполезными.

Ответ 8

Возможно, две вещи, которые следует учитывать помимо того, как вы хотите начать, - это то, что вы хотите фокус, и где вы хотите остановить.

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

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

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

  • Нет необходимости менять код, который работает, и который не нуждается в улучшении. Это приводит к появлению новых ошибок без добавления функциональности, и конечные пользователи этого не понимают;
  • Очень, очень сложно сделать рефакторинг надежно. Многие фрагменты кода настолько велики и также настолько важны, что люди почти не осмеливаются прикоснуться к нему. У нас довольно обширный набор функциональных тестов, но достаточной информации о покрытии кода сложно. В результате трудно установить, имеются ли уже достаточные тесты для выявления проблем во время рефакторинга;
  • ROI трудно установить. Конечный пользователь не будет пользоваться рефакторингом, поэтому он должен быть снижен за счет затрат на обслуживание, что будет увеличиваться изначально, потому что путем рефакторинга вы вводите новые ошибки в зрелые, то есть довольно без ошибок. И сам рефакторинг будет дорогостоящим...

NB. Я полагаю, вы знаете книгу "Работа эффективно с устаревшим кодом"?

Ответ 9

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

Возможно, вам стоит взглянуть на maketea. Он обеспечивает сопоставление образцов для АСТ, а также определение АСТ из абстрактной грамматики и посетителей, трансформеров и т.д.

Ответ 10

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

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

Ответ 11

Вот что я буду делать:

  • Поскольку код составляет 20 лет, замените анализатор синтаксиса синтаксиса и замените его на новый код lex/yacc/bison (или что-то подобное) на основе С++, гораздо удобнее и понятнее. Быстрее развиваться, если у вас есть BNF.
  • Как только это будет обновлено до старого кода, начните обматывать модули в классы. Замените глобальные/общие переменные на интерфейсы.
  • Теперь у вас будет компилятор в С++ (не совсем).
  • Нарисуйте диаграмму классов всех классов в вашей системе и посмотрите, как они общаются.
  • Нарисуйте еще один, используя те же классы и посмотрите, как они должны общаться.
  • Реорганизуйте код, чтобы преобразовать первую диаграмму во вторую. (это может быть грязным и сложным).
  • Не забудьте использовать код С++ для добавления нового кода.
  • Если у вас есть время, попробуйте заменить структуры данных один за другим, чтобы использовать более стандартизованные STL или Boost.