Должна ли "переносимая" компиляция C как С++?
Я получил комментарий к , который я опубликовал по вопросу C, где комментатор предложил, чтобы код был написан для компиляции с компилятором С++, поскольку оригинал упомянутый вопрос должен быть "переносимым".
Является ли это общей интерпретацией "портативного С"? Как я уже сказал в следующем комментарии к этому ответу, это совершенно неожиданно для меня, я считаю, что переносимость означает нечто совершенно иное и очень мало помогает в написании кода C, который также является законным С++.
Ответы
Ответ 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, а не на С++.