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

Должна ли "переносимая" компиляция C как С++?

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

Является ли это общей интерпретацией "портативного С"? Как я уже сказал в следующем комментарии к этому ответу, это совершенно неожиданно для меня, я считаю, что переносимость означает нечто совершенно иное и очень мало помогает в написании кода C, который также является законным С++.

4b9b3361

Ответ 1

Нет. Мой ответ Зачем искусственно ограничивать ваш код C? есть некоторые примеры совместимых со стандартами C99, не компилируемых как С++; ранее C имел меньше различий, но С++ имеет более сильную типизацию и различную обработку списка аргументов функции (void).

Что касается возможности использования C 'portable' на С++, то конкретный проект, на который ссылался в этом ответе, был виртуальной машиной для языка, основанного на чертах, поэтому не подходит для объектной модели С++ и имеет много случаев, когда вы тянете void* стека интерпретатора, а затем конвертируете в структуры, представляющие компоновку встроенных типов объектов. Чтобы сделать код "переносимым" на С++, он бы добавил много отливок, которые ничего не делают для безопасности типов.

Ответ 2

В текущем стандарте С++ (1998) используется стандарт C (1989). Некоторые мелкие шрифты в отношении безопасности типов отложены в сторону, что означает, что "хороший" C89 должен компилироваться в компиляторе С++.

Проблема заключается в том, что текущий стандарт C - это код 1999 года (C99), который еще официально не является частью стандарта С++ (AFAIK) (*). Это означает, что многие из "более приятных" функций C99 (long long int, stdint.h,...), поддерживаемые многими компиляторами С++, не являются строго совместимыми.

"Portable" C означает что-то совсем другое и имеет мало общего с официальными стандартами ISO/ANSI. Это означает, что ваш код не делает предположений в среде хоста. (Размер int, endianess, нестандартные функции или числа errno, такие вещи.)

Из руководства по стилю кодирования, которое я когда-то писал для кросс-платформенного проекта:

Кросс-платформенная ДНК (не допускайте)

  • Нет встроенных типов данных. Единственными типами данных, которые вы можете использовать, являются те, которые указаны в стандартной библиотеке.
  • char, короткие, int и long имеют разные размеры, как float, double и long double.
  • int не 32 бит.
  • char не подписан ни без знака.
  • char не может содержать число, только символы.
  • Превращение короткого типа в более длинный (int → long) правила выравнивания CPU.
  • int и int * имеют разный размер.
  • int * и long * имеют разный размер (как указатели на любой другой тип данных).
  • Вы помните, что родные типы данных даже не существуют?
  • 'a' - 'A' не дает того же результата, что и 'z' - 'Z'.
  • 'Z' - 'A' не дает того же результата, что и 'z' - 'a', и не равен 25.
  • Вы ничего не можете сделать с помощью указателя NULL, за исключением проверки его значения; разыменование, это приведет к сбою системы.
  • Арифметика, включающая как подписанные, так и неподписанные типы, не работает.
  • Правила выравнивания типов данных изменяются случайным образом.
  • Внутренняя компоновка типов данных изменяется случайным образом.
  • Конкретное поведение избыточного и нижнего потоков изменяется случайным образом.
  • Функциональный вызов ABI изменяется случайным образом.
  • Операнды оцениваются в случайном порядке.
  • Только этот компилятор может обойти эту случайность. Случайность изменится со следующей версией процессора/ОС/компилятора.
  • Для указателей == и!= работает только для указателей на один и тот же тип данных.
  • <, > работают только для указателей в один и тот же массив. Они работают только для char явно объявленного unsigned.
  • Вы все еще помните, что родные типы данных не существуют?
  • size_t (тип возвращаемого значения sizeof) не может быть добавлен в какой-либо другой тип данных.
  • ptrdiff_t (тип возвращаемого значения вычитания одного указателя из другого) не может быть добавлен в какой-либо другой тип данных.
  • wchar_t (тип "широкого" символа, точная природа которого определяется реализацией) не может быть добавлена ​​в какой-либо другой тип данных.
  • Любой тип данных..._ t не может быть добавлен в какой-либо другой тип данных.

(*): Это было верно на момент написания. Вещи немного изменились с С++ 11, но суть моего ответа верна.

Ответ 3

Переносимость означает запись вашего кода, так что он компилируется и имеет такое же поведение с использованием разных компиляторов и/или разных платформ (т.е., когда это возможно, полагается на поведение, предусмотренное стандартом ISO).

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

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

Ответ 4

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

И не лишайте себя, скажем, улучшений C99 только для поддержки совместимости с С++.

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

Будучи "хорошим распорядителем", не оставляя мусора вокруг костра, это просто хорошая карма в том, что вы делаете.

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

Ответ 5

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

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

Попробуйте угадать, кто может использовать ваш код, и если вы думаете, что многие поклонники С++ могут найти ваш код полезным, подумайте над тем, чтобы сделать его С++ дружественным. Однако, если вы не думаете, что большинство программистов на С++ нуждаются в нем (т.е. Это функция, которая уже довольно стандартизирована на С++), не беспокойтесь.

Ответ 6

Обычно для компиляции C-кода используется компилятор С++ для более строгой проверки типов. Хотя существуют C-специфические инструменты для этого, например lint, более удобно использовать компилятор С++.

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

Если вам нужно строго соблюдать код C, вам нужно быть осторожным.

Ответ 7

FWIW, как только проект получит определенный размер и импульс, маловероятно, что он может действительно выиграть от совместимости с С++: даже если он не будет перенесен непосредственно на С++, действительно существует many современные инструменты, связанные с работой/обработкой исходного кода на С++.

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

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

Посмотрите, например, на проекты linux (kernel) или gcc, оба из которых в основном "только C", но в сообществах разработчиков регулярно обсуждаются потенциальные преимущества перехода на С++.

И на самом деле в настоящее время продолжается gcc-усилие (в дереве FSF!) для переноса источников gcc в действительный синтаксис С++ (см. gcc-in-cxx для получения подробной информации), так что компилятор С++ может использоваться для компиляции исходного кода.

В основном это было инициировано долгосрочным gcc-хакером: Ян Лэнс Тейлор.

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

Но в конечном итоге эта ветвь предназначена для поощрения миграции к С++ как языка реализации gcc, который является действительно революционным шагом - сдвигом парадигмы, который критически воспринимается теми людьми FSF.

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

Подготовка базы кода gcc для возможного перехода на С++ - это самая логичная вещь (независимо от того, когда она действительно была выполнена, хотя!), и она действительно необходима, чтобы оставаться конкурентоспособной, интересной и простой просто Соответствующий, это относится, в частности, из-за очень многообещающих усилий, таких как llvm, которые не приносят с собой всю эту крутую сложность.

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

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

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

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

Ответ 8

Нет, дело вкуса. Мне не нравится бросать указатели void, загромождает код, который не очень выгоден.

char * p = (char *)malloc(100);

против

char * p = malloc(100);

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

Ответ 9

Почему вы видите небольшую выгоду? Это довольно легко сделать, и кто знает, как вы захотите использовать код в будущем.

Ответ 10

Нет, компиляция с помощью С++ не является общей интерпретацией переносимого. Работа с действительно старым кодом, объявления стиля K & R очень переносимы, но не могут быть скомпилированы под С++.

Как уже указывалось, вы можете использовать усовершенствования C99. Однако я бы посоветовал вам рассмотреть всех ваших целевых пользователей и убедиться, что они могут использовать усовершенствования. Не просто используйте массивы переменной длины и т.д., Потому что у вас есть свобода, но только если это действительно оправдано.

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

Там также аргумент, что запуск компилятора в режиме С++ может получить тонкие ошибки, в зависимости от компилятора, если он применяет различные оптимизации.

Ответ 11

AFAIK весь код в классическом тексте. Язык программирования C, второе издание может быть скомпилирован с использованием стандартных компиляторов С++, таких как GCC (g++). Если ваш код C соответствует стандартам, принятым в этом классическом тексте, то достаточно хорошо, и вы готовы скомпилировать свой C-код с помощью компилятора С++.

Возьмем экземпляр исходного кода ядра Linux, который в основном написан на C с некоторым встроенным кодом ассемблера, это кошмар, компилирующий код ядра Linux с помощью компилятора С++, из-за наименьшей возможной причины, что "новый" используется как имя переменной в Linux-коде ядра, где С++ не разрешает использование "new" в качестве имени переменной. Я просто приводил здесь один пример. Помните, что ядро ​​Linux является портативным и компилируется и отлично работает в архитектурах intel, ppc, sparc и т.д. Это просто иллюстрирует, что переносимость имеет разные значения в мире программного обеспечения. Если вы хотите скомпилировать C-код с помощью компилятора С++, вы переносите свою базу кода с C на С++. Я рассматриваю это как два разных языка программирования по самой очевидной причине, что программистам C не нравится С++. Но я люблю их обоих, и я использую их обоих. Ваш C-код переносимый, но вы должны быть уверены, что следуете стандартным методам, чтобы ваш С++-код был переносимым, когда вы переносите свой код C на код С++. Читайте дальше, чтобы узнать, откуда вы получили стандартные методы.

Вы должны быть очень осторожны, перенося код C на код С++, и следующий вопрос, который я бы спросил, почему бы вам потрудиться, если какой-нибудь кусок кода C переносится и работает без проблем? Я не могу согласиться с управляемостью, опять же Linux-ядро с большим кодом в C управляется очень хорошо.

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

При выборе переносимости используйте следующие правила:

a) Требуется ли компиляция кода (C или С++) на разных архитектурах, возможно, с использованием собственных компиляторов C/С++? b) Изучите компиляторы C/С++ на разных архитектурах, которые вы хотите запустить, и планируете перенос кода. Потратьте время на это. c) Насколько это возможно, попробуйте обеспечить чистый уровень разделения между кодом C и кодом С++. Если ваш C-код переносимый, вам просто нужно снова написать С++-оболочки вокруг этого портативного C-кода, используя переносимые методы кодирования на С++.

Повернитесь на некоторые хорошие книги на С++ о том, как писать переносимый код на С++. Я лично рекомендую язык программирования С++ самим Bjarne Stroustrup, эффективные серии С++ от Scott meyers и популярные статьи DDJ на сайте www.ddj.com.

PS: пример ядра Linux в моем сообщении - это просто иллюстрировать, что переносимость означает различные значения в программном программировании и не критикует, что ядро ​​Linux написано на C, а не на С++.