Может ли код, корректный и в C, и в C++, вести себя по-разному?
Да, такой код существует: классический пример — неявное приведение void*
Ваш пример с sizeof действительно показывает разницу в размерах массива и указателя, но это не является разным поведением — оба языка ведут себя одинаково: sizeof(arr) возвращает 6 (5 символов + '\0'), а sizeof(ptr) возвращает размер указателя (4 или 8 байт). Разное поведение — это когда один и тот же код даёт разные результаты или компилируется/не компилируется.
Вот самый известный пример, который демонстрирует разное поведение:
// Файл: test.c / test.cpp
#include <stdlib.h>
int main() {
int *p = malloc(sizeof(int) * 10); // Ошибка в C++, но не в C
free(p);
return 0;
}
Почему это работает по-разному?
- В языке C:
malloc()возвращаетvoid*, который неявно преобразуется к любому типу указателя. Код корректен. - В языке C++:
malloc()возвращаетvoid*, но неявное приведение кint*запрещено. Компилятор выдаст ошибку:error: invalid conversion from 'void*' to 'int*'.
Чтобы код работал в C++, нужно явное приведение:
int *p = (int*)malloc(sizeof(int) * 10);
Другой пример: ключевые слова-синонимы
В C++ есть ключевые слова, которых нет в C, например bool, true, false. Если в коде C вы используете bool как имя переменной, это будет корректно. В C++ — ошибка:
// Валидный C, но не C++
int bool = 5; // C++: error: 'bool' is a keyword
Третий пример: sizeof('a')
Этот пример особенно коварен:
#include <stdio.h>
int main() {
printf("sizeof('a') = %zu\n", sizeof('a'));
return 0;
}
- В C: символьный литерал
'a'имеет типint, поэтомуsizeof('a')равенsizeof(int)— обычно 4. - В C++: символьный литерал
'a'имеет типchar, поэтомуsizeof('a')равен 1.
Как избежать проблем?
- Не пишите код, который должен быть одновременно валидным в C и C++. Если проект на C++ — используйте C++-стиль (new/delete вместо malloc/free, явные приведения).
- Используйте компилятор с флагами строгой проверки. Для GCC:
-Wall -Wextra -pedantic. - Проверяйте типы. В C++ всегда используйте
static_cast<>вместо C-style приведения.
В итоге: да, такой код существует. Он редок, но может стать источником трудноуловимых багов, особенно при переносе legacy C-кода в C++.
<<Дополнение: разные правила для enum и struct
Ещё один важный случай — объявление структур и перечислений.
В C++ вы можете ссылаться на структуру без ключевого слова struct:
// Валидный C++
struct Point { int x; int y; };
Point p; // OK в C++, но ошибка в C
В C нужно писать struct Point p; или использовать typedef. Если вы забудете typedef в C, код не скомпилируется, а в C++ — сработает.
Также разное поведение у enum в C и C++:
- В C:
enum Color { RED, GREEN, BLUE };— это отдельный тип, но его значения можно неявно преобразовывать вint. - В C++: начиная с C++11,
enum classтребует явного преобразования. Обычныйenumтоже ведёт себя строже.
Поэтому при портировании кода из C в C++ всегда проверяйте объявления структур и перечислений — это частая причина ошибок компиляции.