2017-01-08 3 views
4

Я только что прочитал: C Wikipedia entry. Насколько я знаю, существуют 3 различных версии C, которые широко используются: C89, C99 и C11. Мой вопрос касается совместимости исходного кода разных версий. Предположим, что я собираюсь написать программу (в C11, так как это последняя версия) и импортировать библиотеку, написанную на C89. Правильно ли эти две версии будут работать вместе при компиляции всех файлов в соответствии со спецификацией C11?Совместимость C89/C90, C99 и C11

Вопрос 1: Являются ли более поздние версии C i.e. C99, C11 более ранними версиями C? По superset я имею в виду, что старый код будет компилироваться без ошибок и того же значения при компиляции в соответствии с новыми спецификациями C.

Я только что прочитал, что // имеет разные значения в C89 и C99. Помимо этой функции, C99 и C11 надмножества C89?

Если ответ на вопрос 1 нет, то у меня есть еще 2 вопроса.

  1. Как переносить старый код в новые версии? Есть ли документ, который объясняет эту процедуру?

  2. Лучше ли использовать C89 или C99 или C11?

Спасибо за вашу помощь заранее.

EDIT: изменено ISO C на C89.

+1

Вы продолжаете говорить ISO C, но я думаю, вы имеете в виду ANSI C (или C89 или C90, все три из этих имен относятся к одному и тому же языку). ISO C сам по себе ничего не значит (и важно отметить, что как C99, так и C11 определяются органами языка ISO). – Cornstalks

+1

@Cornstalks Технически каждый стандарт ISO C заменяет своих предшественников, и ANSI использует стандарты языка ISO C, поэтому «ANSI C» будет означать также C11. (Но большинство людей этого не используют). – melpomene

+1

https://github.com/mauke/poly.poly/blob/master/poly.poly может различать C89 и C99 (путем компиляции с разными семантиками в каждом) , поэтому ответ на Q1 «нет». – melpomene

ответ

7

Являются ли более новые версии C i.e. C99, C11 более поздними версиями C?

Есть много отличий, большие и тонкие оба. Большинство изменений заключалось в добавлении новых функций и библиотек. C99 и C11 не являются суперсетями C90, хотя было сделано много усилий для обеспечения обратной совместимости. C11, однако, в основном представляет собой надмножество C99.

Еще старый код может сломаться при портировании с C90, если код был написан плохо. В частности, различные формы «неявных int» и неявных деклараций функций были запрещены на языке C99. C11 запретил функцию gets.

Полный список изменений можно найти в черновике C11 стр. 13 из pdf, где «третье издание» относится к C11, а «второе издание» относится к C99.

Как переносить старый код в новые версии? Есть ли документ, который объясняет эту процедуру?

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

Помещение от C99 до C11 должно быть легким.

Лучше ли использовать C89 или C99 или C11?

Лучше всего использовать C11, поскольку это текущий стандарт. C99 и C11 содержали различные «исправления языковых ошибок» и вводили новые полезные функции.

+0

Спасибо за помощь. У меня возникает другой вопрос: вы сказали, что лучше использовать C11. Затем я прочитал следующее: http://stackoverflow.com/questions/20600497/which-c-version-is-used-in-the-linux-kernel#20664429 Почему ядро ​​Linux использует диалект GNU C89? –

+1

@MichaelS Я бы предположил, что это было бы потому, что Linux был создан в конце 90-х, когда ни C99, ни C11 не были вокруг. При этом ядро ​​Linux является невероятно грязной базой кода, заполненной до краев нестандартными расширениями gcc, до такой степени, что этот код навсегда застрял в gcc. Почему они делают что-то определенным образом, я понятия не имею, но я буду искать в другом месте для вдохновения, так как база ядра ядра Linux примерно такая же, как и у вас, канона. Точно так же руководство по стилю кода ядра Linux не является стандартом профессионального кодирования. – Lundin

+0

Спасибо за ваш ответ и помощь!Прошу прощения, но я не могу поддержать ваши комментарии и ответы, поскольку у меня недостаточно репутации. –

0

В целом, более новые версии стандарта являются обратными.

Если нет, вы можете скомпилировать различные файлы .c в разные файлы .o с использованием разных стандартов и связать их вместе. Это работает.

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

EDIT: Если вы не имеете дело с потенциально неопределенным поведением.

+1

В стандартах есть некоторые семантические изменения, которые приводят к определенным конструкциям, которые использовали определенное поведение (например, некоторые использования «memcpy» или «memmove» для типа punning в случаях, когда адресат не имеет объявленного типа, но будет считываться с использованием типа без представления ловушек) вместо этого вызывать Undefined Behavior. Спецификация различных стандартных версий при компиляции может оказаться недостаточной для достижения правильного поведения, однако, если компиляторы делают вид, что такое поведение никогда не было определено, несмотря на отсутствие чего-либо в более старых стандартах, чтобы оправдать такое убеждение. – supercat

+0

Ну, это на самом деле хороший момент. –

0

Новейшие версии C, безусловно, не являются строгими супер-наборами более старых версий.

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

Если можно определить, лучшим стандартом для использования является тот, который поддерживает лучший компилятор.

C11 wikipedia article имеет подробное описание того, как он отличается от C99.

1

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

Более важная проблема, однако, связана с псевдонимом памяти. C89 включают в себя правила , которые ограничивают типы указателей, которые могут использоваться для доступа к определенным объектам . Поскольку правила сделали бы такие функции, как malloc() бесполезными, если они применили, как написано, к созданным им объектам, большинство программистов и писатели-компиляторы рассматривали правила как применяющие только в ограниченных случаях (я сомневаюсь, что C89 был бы широко принято, если люди не считают, что правила применяются только узко). C99 утверждал, что «разъясняет» правила, но его новые правила гораздо более экспансивны по сравнению с одновременными интерпретациями старых, нарушая много кода, который бы определял поведение в рамках общих интерпретаций C89, и даже некоторый код, который было бы однозначно определено в разделе C89, не имеющем практического эквивалента C99.

В C89, например, memcpy может использоваться для копирования битового шаблона, связанного с объектом любого типа, с объектом любого другого типа с одинаковым размером, в любом случае, когда этот бит-шаблон будет представлять допустимое значение в типе назначения. C99 добавил язык, который позволяет компиляторам вести себя произвольно, если memcpy используется для копирования объекта некоторого типа T в хранилище без объявленного типа (например,хранилище, возвращаемое с malloc), и это хранилище затем считывается как объект типа, который не является псевдонимом, совместимым с T, даже если бит-шаблон исходного объекта будет иметь действительное значение в новом типе. Кроме того, правила, применимые к memcpy, также применяются в случаях, когда объект копируется как массив типа символа - без каких-либо уточнений, что это значит, - поэтому неясно, какой именно код нужно будет сделать для достижения поведения, соответствующего C89 memcpy.

Во многих компиляторах такие проблемы могут быть решены путем добавления в командной строке опции -fno-strict-aliasing. Обратите внимание, что указание режима C89 может быть , но не, поскольку авторы-компиляторы часто используют одну и ту же семантику памяти независимо от того, какой стандарт они должны выполнять.

Смежные вопросы