Введение: Один язык — десятки расширений
Если вы только начинаете изучать C++, то наверняка сталкивались с ситуацией: смотрите учебник или пример кода на GitHub, а там файлы называются то main.cpp, то utils.cc, а иногда и вовсе program.cxx или source.C. Возникает закономерный вопрос: "А в чём разница? Это разные языки? Или просто чей-то каприз?"
Вы не одиноки. На Stack Overflow вопрос "C++ code file extension? What is the difference between .cc and .cpp" собрал сотни тысяч просмотров. И это неудивительно: даже опытные разработчики иногда путаются в этих, казалось бы, мелочах. Сегодня мы раз и навсегда разберёмся с этой головоломкой. Вы узнаете, откуда взялись разные расширения, есть ли между ними техническая разница и какое расширение стоит выбрать новичку.
Краткий ответ: технической разницы нет
Давайте сразу снимем главное напряжение. С точки зрения компилятора и языка C++, между .cc и .cpp нет абсолютно никакой разницы. Это просто два разных способа сообщить операционной системе и инструментам сборки, что перед ними — исходный код на C++.
Компиляторы (GCC, Clang, MSVC) понимают оба расширения. Вы можете взять файл hello.cc, переименовать его в hello.cpp и скомпилировать без единого изменения в коде. Вот простой пример:
// Файл: hello.cc
#include <iostream>
int main() {
std::cout << "Привет из .cc файла!" << std::endl;
return 0;
}
Скомпилировать его можно так:
g++ hello.cc -o hello
А теперь переименуем его в hello.cpp:
g++ hello.cpp -o hello
Результат будет идентичным. Компилятору всё равно, как называется файл — важно только его содержимое и то, что вы явно указали язык (или компилятор догадался по расширению).
История происхождения: откуда взялись .cc и .cpp?
Чтобы понять, почему существует так много расширений, нужно заглянуть в историю. C++ создавался как расширение языка C. Первые компиляторы (например, Cfront) были просто препроцессорами, которые транслировали C++ в обычный C.
Расширение .cc — Unix-наследие
В операционных системах семейства Unix (и в частности, в ранних версиях AT&T Unix) сложилась традиция использовать короткие, двухсимвольные расширения. Это было связано с ограничениями файловых систем: например, в s5fs (System V) длина имени файла была сильно ограничена. Так появились:
.c— для C-файлов.cc— для C++ файлов (C + C = CC).h— для заголовочных файлов
Расширение .cc стало стандартом де-факто в мире Unix и Linux. Многие крупные проекты (например, Google Chromium, LLVM) до сих пор используют именно его.
Расширение .cpp — эпоха DOS и Windows
Когда C++ начал набирать популярность в мире PC, появилась экосистема DOS и ранних версий Windows. Здесь ограничения были другими, но возникла другая потребность — сделать расширение максимально понятным. .cpp расшифровывается как C Plus Plus — прямое указание на язык. Это расширение стало популярным благодаря:
- Среде разработки Borland C++
- Microsoft Visual C++
- Учебникам и книгам по C++ (чтобы новички сразу понимали, с чем имеют дело)
Другие расширения-путешественники
Кроме двух главных претендентов, в мире C++ можно встретить и другие расширения:
.cxx— ещё один вариант "C++", популярен в некоторых Unix-системах (например, IBM AIX).C(заглавная C) — используется некоторыми компиляторами для различения C (.c) и C++ (.C) на системах, где регистр имеет значение (например, в старых версиях GCC).c++— самый буквальный вариант, но неудобен для файловых систем, так как содержит спецсимволы
Есть ли скрытые технические нюансы?
Хотя компилятору всё равно, есть несколько практических моментов, которые стоит знать.
Автоматическое определение языка компилятором
Большинство современных компиляторов (GCC, Clang) определяют язык исходного файла именно по расширению. Если вы дадите файлу расширение .c, GCC подумает, что это C, и будет компилировать его как C-код (а C++ код в файле с .c вызовет ошибки). С расширениями .cc, .cpp, .cxx и .C компилятор понимает, что это C++.
// Файл: test.c (компилятор считает это C-кодом)
#include <iostream> // Ошибка! В C нет iostream
int main() {
std::cout << "Привет!" << std::endl;
return 0;
}
Попытка скомпилировать такой файл как C приведёт к ошибке. Но если переименовать его в test.cc, всё заработает.
Системы сборки и Makefile
Если вы используете системы сборки вроде CMake, Make или Bazel, они часто имеют встроенные правила для разных расширений. Например, в Makefile можно встретить такое:
SOURCES = main.cpp utils.cc helper.cxx
OBJECTS = $(SOURCES:.cpp=.o)
OBJECTS := $(OBJECTS:.cc=.o)
OBJECTS := $(OBJECTS:.cxx=.o)
Разработчику приходится явно указывать все возможные расширения, чтобы система сборки обработала все файлы. Поэтому в больших проектах стремятся к единообразию.
Инструменты линтинга и статического анализа
Некоторые инструменты (например, старые версии Cppcheck или линтеры) могут по-разному реагировать на расширения. Но в 2024 году это уже редкость — все современные инструменты прекрасно работают с любым стандартным расширением C++.
Практический совет для начинающих: что выбрать?
Итак, вы стоите перед выбором: .cc или .cpp? Вот несколько рекомендаций, основанных на реальной практике.
Выберите .cpp, если вы новичок
Вот почему .cpp — лучший выбор для начинающих:
- Понятность. Расширение
.cppинтуитивно понятно: "C Plus Plus". Вы сразу видите, что это файл на C++.