GCC vs G++: В чем разница и какой компилятор C++ выбрать?

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: Драма с двумя именами

Если вы когда-нибудь пытались скомпилировать программу на C++ в Linux или macOS, то наверняка сталкивались с двумя похожими командами: gcc и g++. На первый взгляд, разница между ними минимальна — оба запускают компилятор, оба умеют работать с C и C++. Но стоит ошибиться с выбором, и вы получаете гору ошибок линковки, которые способны испортить вечер даже опытному разработчику.

Этот вопрос — один из самых популярных на Stack Overflow (более 200 000 просмотров!). Новички часто думают: «Раз gcc умеет компилировать C++, зачем нужен g++?» А зря. Сегодня мы раз и навсегда разберемся, в чем подвох, на реальных примерах кода. Вы узнаете, когда использовать gcc, когда — g++, и как не попасть в ловушку неявных зависимостей.

Краткий экскурс: что такое GCC?

GCC (GNU Compiler Collection) — это не один компилятор, а целый набор инструментов. В него входят компиляторы для C, C++, Fortran, Ada и других языков. Исторически аббревиатура расшифровывалась как «GNU C Compiler», но с годами проект разросся.

Команда gcc — это драйвер, который по умолчанию запускает компилятор для языка C. Команда g++ — тот же драйвер, но с флагами, которые включают поддержку C++. Казалось бы, мелочь. Но именно эта «мелочь» решает, будет ли ваш код работать.

Главное отличие: линковка стандартных библиотек

Представьте, что вы пишете простую программу на C++:

#include <iostream>
int main() {
    std::cout << "Привет, мир!" << std::endl;
    return 0;
}

Попробуем скомпилировать её двумя способами:

gcc main.cpp -o program_gcc
g++ main.cpp -o program_gpp

Результат:

  • g++ — компиляция пройдет успешно.
  • gcc — вы получите ошибку линковки undefined reference to `std::cout'.

Почему? Потому что gcc не подключает автоматически библиотеку libstdc++ (стандартную библиотеку C++). Он думает, что вы компилируете чистый C, а в C нет iostream, std::string и других радостей C++. g++ же делает это автоматически.

Конечно, вы можете заставить gcc работать с C++ вручную, добавив флаг -lstdc++:

gcc main.cpp -lstdc++ -o program_gcc_fixed

Но зачем изобретать велосипед? g++ делает это «из коробки».

А что насчет компиляции чистого C?

Тут всё симметрично. Если вы напишете программу на C и попытаетесь скомпилировать её через g++, она, скорее всего, сработает. Но g++ будет трактовать код как C++, а это значит:

  • Более строгие проверки типов.
  • Другие правила для неявного приведения типов.
  • Возможны ложные предупреждения (warnings).

Пример. Код на C:

#include <stdio.h>
int main() {
    char *s = malloc(100);
    printf("Hello\n");
    free(s);
    return 0;
}

В C это нормально. В C++ нужно явное приведение (char*)malloc(100). g++ выдаст ошибку, а gcc — нет. Вывод: для C-проектов используйте gcc, для C++ — g++.

Расширения файлов: как компилятор понимает язык?

Еще один важный нюанс: gcc и g++ смотрят на расширение файла.

  • .c — компилируется как C.
  • .cpp, .cc, .cxx — компилируется как C++.

Если вы дадите gcc файл с расширением .cpp, он поймет, что это C++, и использует правильный фронтенд (компилятор языка). Но линковка всё равно останется без libstdc++! Это ловушка, в которую попадаются многие: код компилируется, но линковка падает.

Проверим:

// файл test.cpp
#include <vector>
int main() {
    std::vector<int> v;
    v.push_back(42);
    return 0;
}
gcc -c test.cpp          # OK, объектный файл test.o создан
gcc test.o -o test       # ОШИБКА линковки!

Мораль: если вы используете C++ библиотеки (а вы их используете почти всегда), просто пишите g++. Это сэкономит вам часы дебага.

Практический пример: смешанный проект C и C++

Иногда в одном проекте есть код на C и на C++. Как быть? Тут нужна комбинация.

Допустим, у вас есть функция на C:

// utils.c
#include <stdio.h>
void print_message(const char *msg) {
    printf("%s\n", msg);
}

И основная программа на C++:

// main.cpp
extern "C" {
    void print_message(const char*);
}

int main() {
    print_message("Привет из C++!");
    return 0;
}

Компилируем так:

gcc -c utils.c -o utils.o      # Компилируем C-часть
g++ -c main.cpp -o main.o      # Компилируем C++-часть
g++ utils.o main.o -o program  # Линкуем через g++ (авто-линковка libstdc++)

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

Мифы и заблуждения

Миф 1: «g++ — это просто gcc с флагом -x c++»

Не совсем. g++ автоматически добавляет -lstdc++ и устанавливает несколько внутренних флагов. Флаг -x c++ только меняет

Блоги

Рекомендаций по книгам