Нижеприведенный список является моей небольшой коллекцией примеров кода на языке С, которые не являются корректными с точки зрения языка С++ или имеют какое-то специфичное именно для языка С поведение. (Именно в эту сторону: С код, являющийся некорректным с точки зрения С++.)
Этот материал я уже публиковал на другом ресурсе в менее причесанном виде, Я бы, наверное, поддался прокрастинации и никогда не собрался опубликовать эту коллекцию здесь, но из-за горизонта уже доносится стук копыт неумолимо приближающегося С23, который безжалостно принесет некоторые жемчужины моей коллекции в жертву богам С-С++ совместимости. Поэтому мне и пришлось встать с печи, пока они еще актуальны…
Разумеется, язык С имеет много существенных отличий от языка С++, т.е. не составит никакого труда привести примеры несовместимостей, основанные, скажем, на ключевых словах или других очевидных эксклюзивных свойствах С99. Таких примеров вы не найдете в списке ниже. Мой основной критерий для включения примеров в этот список заключался именно в том, что пример кода должен выглядеть на первый взгляд достаточно «невинно» для С++-наблюдателя, т.е. не содержать бросающихся в глаза С-эксклюзивов, но тем не менее являться специфичным именно для языка С.
(Пометка [C23] помечает те пункты, которые станут неактуальными с выходом C23.)
-
В языке C разрешается «терять» замыкающий
\0при инициализации массива символов строковым литералом:char s[4] = "1234";В С++ такая инициализация является некорректной.
-
C поддерживает
Такой формат для
printfкорректен c точки зрения C, но некорректен с точки зрения C++. -
Рекурсивные вызовы функции
mainразрешены в C, но запрещены в C++. Программам на С++ вообще не дозволяется никак использовать основную функциюmain. -
В языке C строковые литералы имеют тип
char [N], а в языке C++ —const char [N]. Даже если считать, что «старый» C++ в виде исключения поддерживает преобразование строкового литерала к типуchar *, это исключение работает только тогда, когда оно применяется непосредственно к строковому литералуchar *p = &"abcd"[0];Такая инициализация некорректна с точки зрения C++.
-
В языке С битовое поле, объявленное с типом
intбез явного указанияsignedилиunsignedможет быть как знаковым, там и беззнаковым (определяется реализацией). В языке С++ такое битовое поле всегда является знаковым. -
В языке С typedef-имена типов и тэги struct-типов располагаются в разных пространствах имен и не конфликтуют друг с другом. Например, такой набор объявлений корректен с точки зрения языка С:
struct A { int a; }; typedef struct B { int b; } A; typedef struct C { int c; } C;В языке С++ не существует отдельного понятия тэга для класс-типов: имена классов разделяют одно пространство имен с typedef-именами и могут конфликтовать с ними. Для частичной совместимости с кодом на С язык С++ разрешает объявлять typedef-псевдонимы, совпадающие с именами существующих класс-типов, но только при условии, что псевдоним ссылается на класс-тип с точно таким же именем. В вышеприведенном примере typedef-объявление в строке 2 некорректно с точки зрения C++, а объявление в строке 3 — корректно.
-
В языке С разрешается использовать имя поля, совпадающее с существующим именем типа
typedef int I; struct S { I I; };В языке С++ такое «переопределение» идентификатора не допускается.
-
В языке С неявный конфликт между внутренним и внешним связыванием при объявлении одной и той же переменной приводит к неопределенному поведению, а в языке С++ такой конфликт делает программу https://habr.com/ru/articles/680312/
Добавить комментарий