Avatar ·

В чем разница между g++ и gcc при компиляции кода на C++?

Привет всем! Я только начал изучать C++ и компилирую свои программы через терминал. Раньше я писал на C, и использовал команду gcc для компиляции. Теперь, когда я перешел на C++, я заметил, что многие в туториалах используют g++ вместо gcc. Я попробовал скомпилировать простой код на C++ с помощью gcc, и он выдал ошибки. Например, вот мой код:
#include <iostream>
int main() {
    std::cout << "Hello, world!" << std::endl;
    return 0;
}
Когда я запускаю `gcc test.cpp -o test`, я получаю кучу ошибок линковки, вроде `undefined reference to std::cout`. Но если я запускаю `g++ test.cpp -o test`, все работает отлично. В чем здесь разница? Это просто разные версии одного компилятора? Или они делают что-то принципиально разное? Нужно ли мне всегда использовать g++ для C++ кода, или можно как-то настроить gcc? Буду благодарен за развернутое объяснение! <<>>

Ключевое отличие: g++ — это надстройка над gcc для C++

На самом деле, и gcc, и g++ — это часть одного набора компиляторов GNU Compiler Collection (GCC). gcc — это "драйвер" компилятора, который умеет работать с разными языками (C, C++, Objective-C, Fortran и т.д.), но по умолчанию он настроен на компиляцию кода на C. g++ — это тот же драйвер, но с автоматической настройкой на C++.

Вот основные различия в поведении:

  • Автоматическое подключение библиотек: Когда вы используете g++, он автоматически линкует вашу программу со стандартной библиотекой C++ (libstdc++). Именно поэтому std::cout, std::string и другие объекты из <iostream> работают "из коробки". gcc этого не делает — он линкует только с библиотекой C (libc).
  • Определение языка по расширению: gcc определяет язык программирования по расширению файла. Файлы .c он компилирует как C, а файлы .cpp — как C++. Однако, даже если gcc скомпилирует C++ код, он все равно не подключит библиотеку C++ при линковке.
  • Исключение с C++: Если вы явно укажете gcc -x c++, компилятор будет обрабатывать код как C++, но без линковки с libstdc++. Это все равно вызовет ошибки линковки для кода, использующего стандартную библиотеку C++.

Что происходит под капотом?

Когда вы выполняете g++ test.cpp -o test, компилятор делает следующее:

  1. Запускает препроцессор (cpp) для обработки директив #include и макросов.
  2. Компилирует код в объектный файл (test.o).
  3. Линкует объектный файл с библиотеками: libstdc++ (для C++) и libc (для C), а также добавляет рантайм-код C++ (например, для обработки исключений и инициализации глобальных объектов).

При использовании gcc test.cpp -o test шаги 1 и 2 выполняются так же (если расширение файла .cpp), но на шаге 3 линковка происходит только с libc. Поэтому компилятор не находит определения для std::cout — он объявлен в заголовке <iostream>, но определен в библиотеке libstdc++, которая не подключена.

Как заставить gcc работать с C++?

Теоретически, вы можете заставить gcc скомпилировать C++ код, если вручную укажете библиотеку для линковки:

gcc test.cpp -lstdc++ -o test

Флаг -lstdc++ явно подключает библиотеку C++. Однако это избыточно и не рекомендуется. Вот почему:

  • g++ сам добавляет правильные флаги для инициализации глобальных объектов C++ (например, конструкторы статических объектов).
  • g++ корректно обрабатывает исключения C++ (включая раскрутку стека).
  • При использовании gcc -lstdc++ вы можете случайно пропустить другие важные флаги, специфичные для C++.

Итог

Всегда используйте g++ для компиляции кода на C++. Это правильный и безопасный способ. gcc оставьте для чистого кода на C. Если вы видите, что кто-то использует gcc для C++, скорее всего, это либо старый учебник, либо человек вручную добавляет все флаги, что чревато ошибками.

<<>>

Дополнение: Когда разница особенно заметна

Первый ответ отлично объясняет основу. Хочу добавить пару практических моментов, которые помогут вам избежать типичных ошибок новичков.

1. Компиляция смешанного кода (C и C++). Если у вас в проекте есть файлы и на C (.c), и на C++ (.cpp), вы можете использовать g++ для линковки всех объектных файлов. Он сам разберется, какие библиотеки подключать. Например:

g++ -c main.cpp -o main.o   # компиляция C++
gcc -c helper.c -o helper.o  # компиляция C
g++ main.o helper.o -o program  # линковка всего вместе

2. Проверка версий. Иногда на старых системах gcc может быть настроен как символическая ссылка на g++, но это редкость. Проверить, что именно вызывается, можно командами gcc --version и g++ --version. Если они показывают одинаковую версию — все в порядке, но поведение все равно будет разным из-за автоматических флагов.

3. Makefile и CMake. Если вы пишете Makefile вручную, используйте переменную CXX для C++ компилятора (CXX = g++) и CC для C (CC = gcc). Это стандарт, и его придерживаются все инструменты сборки. В CMake это делается автоматически: при включении языка C++ (enable_language(CXX)) используется g++.

Запомните простое правило: .c → gcc, .cpp → g++. Это избавит вас от 99% проблем с линковкой.