Последние несколько месяцев я программировал на простом C из-за нашей университетской программы. Программы, которые я пишу, довольно маленькие и очень нетребовательны к ресурсам. В результате компиляция с помощью gcc всегда была почти мгновенным процессом (40 мс в моей «самой большой» программе на данный момент).
Однако недавно я принял участие в местном конкурсе, для которого C++, очевидно, является нормой, и начал практиковаться. Несмотря на то, что мои программы по-прежнему очень малы (не более половины КБ), я заметил, что компиляция с помощью g++ постоянно была почти как пауза в 0,2 секунды, за которой следовала мгновенная компиляция, к которой я привык с помощью gcc.
Вот код, на котором я сейчас его тестирую:
//#include <bits/stdc++.h> // I commented this out thinking that maybe the problem was due to too many header files being included
#include <iostream>
#include <vector>
#include <algorithm>
#include <climits>
using namespace std; // I know this is kind of a bad practice but I've been told it's recommended in competitions for ease of writing
int mex(vector<int> arr, vector<int> subarr) {
int min = INT_MAX;
for (auto i : arr) {
// If i doesn't exist in subarr
if (find(subarr.begin(), subarr.end(), i) == subarr.end()) {
if (i < min) {
min = i;
}
}
}
return min;
}
int main () {
vector<int> a = {0,1,2,3,4,5};
vector<int> suba = {0, 1,3,4};
cout << mex(a, suba) << endl;
return 0;
}
Это компилируется за 240 мс.
Вот g++ ftime-report:
Time variable usr sys wall GGC
phase setup : 0.00 ( 0%) 0.00 ( 0%) 0.00 ( 0%) 1562k ( 2%)
phase parsing : 0.16 ( 84%) 0.13 ( 87%) 0.29 ( 85%) 60M ( 83%)
phase lang. deferred : 0.01 ( 5%) 0.01 ( 7%) 0.02 ( 6%) 5818k ( 8%)
phase opt and generate : 0.02 ( 11%) 0.01 ( 7%) 0.03 ( 9%) 5468k ( 7%)
|name lookup : 0.05 ( 26%) 0.02 ( 13%) 0.03 ( 9%) 2550k ( 3%)
|overload resolution : 0.01 ( 5%) 0.00 ( 0%) 0.02 ( 6%) 6891k ( 9%)
callgraph construction : 0.01 ( 5%) 0.00 ( 0%) 0.01 ( 3%) 1448k ( 2%)
df scan insns : 0.01 ( 5%) 0.00 ( 0%) 0.00 ( 0%) 4128 ( 0%)
preprocessing : 0.01 ( 5%) 0.05 ( 33%) 0.05 ( 15%) 1805k ( 2%)
parser (global) : 0.03 ( 16%) 0.02 ( 13%) 0.07 ( 21%) 16M ( 23%)
parser struct body : 0.00 ( 0%) 0.03 ( 20%) 0.03 ( 9%) 11M ( 15%)
parser function body : 0.03 ( 16%) 0.00 ( 0%) 0.03 ( 9%) 3231k ( 4%)
parser inl. func. body : 0.01 ( 5%) 0.02 ( 13%) 0.01 ( 3%) 1474k ( 2%)
parser inl. meth. body : 0.01 ( 5%) 0.00 ( 0%) 0.03 ( 9%) 5790k ( 8%)
template instantiation : 0.07 ( 37%) 0.02 ( 13%) 0.08 ( 24%) 19M ( 27%)
constant expression evaluation : 0.00 ( 0%) 0.00 ( 0%) 0.01 ( 3%) 85k ( 0%)
expand : 0.00 ( 0%) 0.01 ( 7%) 0.00 ( 0%) 367k ( 0%)
integrated RA : 0.00 ( 0%) 0.00 ( 0%) 0.00 ( 0%) 2092k ( 3%)
LRA non-specific : 0.00 ( 0%) 0.00 ( 0%) 0.01 ( 3%) 14k ( 0%)
symout : 0.01 ( 5%) 0.00 ( 0%) 0.00 ( 0%) 6907k ( 9%)
rest of compilation : 0.00 ( 0%) 0.00 ( 0%) 0.01 ( 3%) 212k ( 0%)
TOTAL : 0.19 0.15 0.34 73M
Я использую версии gcc и g++ 11.4.0 в Ubuntu 22.04.
Это нормальное явление? Обычно g++ заметно медленнее, чем gcc? Или у меня на компьютере какая-то проблема?
Средний заголовок включения C++ увеличивает время компиляции гораздо больше, чем средний заголовок включения POSIX/стандарта C. Заголовки C также могут замедлять компиляцию, особенно если они содержат много встроенных функций (макросы анализируются намного быстрее, чем встроенные функции). Но заголовки POSIX/standard-C обычно представляют собой всего лишь несколько определений типов и объявлений с редким #define.
Вероятно, вы можете ускорить локальную компиляцию, включив все стандартные заголовки в отдельный файл в виде предварительно скомпилированного заголовка . Вы по-прежнему можете сделать свой код доступным для отправки, используя какой-либо макрос, который вы определяете локально. Если он не определен, не используйте предварительно скомпилированный заголовок, а вместо этого включите все встроенное в основной исходный файл.





Да, это нормально. Язык C++ намного сложнее, чем язык C, и в стандартных заголовках содержится больше возможностей.
Создание проектов корпоративного уровня может занять несколько часов, так что будьте очень рады, что ваш проект займет всего 0,2 секунды!
Да, по моему опыту, это довольно распространенное явление, поскольку C++ имеет множество функций и более сложный синтаксис.
Если ваш код не использует никаких функций C++, время компиляции может быть практически идентичным, но использование C++ требует гораздо большего количества проверок и логики, что усложняет процесс.
Более подробное объяснение причины вы можете найти здесь
Теоретически, C должен иметь преимущество в скорости синтаксического анализа, поскольку в отличие от C++ у него почти контекстно-свободная грамматика. На практике скорости синтаксического анализа очень похожи (C++ лишь на несколько процентов медленнее), а реальная проблема — большие (раздутые) заголовки со множеством встроенных функций в STL.
Компиляции C также могут замедляться из-за заголовков со многими встроенными функциями (в меньшей степени из-за макросов), но на практике их не так много, по крайней мере, в обычных.
В Linux вы можете включить все заголовки posix одновременно, затратив время компиляции в несколько десятков мс (незаметно для человека) для всех из них вместе. По сравнению с этим, один заголовок STL может легко добавить сотни мс ко времени компиляции одного файла (заметная задержка).
Вот небольшой bash-скрипт с некоторой информацией (создает/удаляет файлы в текущем каталоге!!):
#!/bin/bash -eu
for i in {0..1000}; do echo "int f$i(void){return $i;}"; done > funcs.c
for i in {0..1000}; do echo "static inline int i$i(void){return $i;}"; done > inls.c
for i in {0..1000}; do echo "#define M$i() $i"; done > macs.c
echo " " > empty.c
echo "#include <vector>" > incl_vector.cc
echo "#include <string>" > incl_string.cc
echo "#include <iostream>" > incl_iostream.cc
echo "#include <string.h>" > incl_string.c
echo "#include <stdio.h>" > incl_stdio.c
TIMEFORMAT=%Rs
: ${CC:=gcc}
set -x
time $CC -xc -Os empty.c -c
time $CC -xc -Os funcs.c -c
time $CC -xc -Os inls.c -c
time $CC -xc -Os macs.c -c
time $CC -xc -Os incl_string.c -c
time $CC -xc -Os incl_stdio.c -c
time $CC -xc++ -Os empty.c -c
time $CC -xc++ -Os funcs.c -c
time $CC -xc++ -Os inls.c -c
time $CC -xc++ -Os macs.c -c
time $CC -xc++ -Os incl_vector.cc -c
time $CC -xc++ -Os incl_string.cc -c
time $CC -xc++ -Os incl_iostream.cc -c
Я получаю (более старая машина (Sandy Bridge i7) с gcc-13):
+ gcc -xc -Os empty.c -c
0.015s
+ gcc -xc -Os funcs.c -c
0.808s
+ gcc -xc -Os inls.c -c
0.031s
+ gcc -xc -Os macs.c -c
0.015s
+ gcc -xc -Os incl_string.c -c
0.017s
+ gcc -xc -Os incl_stdio.c -c
0.020s
+ gcc -xc++ -Os empty.c -c
0.015s
+ gcc -xc++ -Os funcs.c -c
0.860s
+ gcc -xc++ -Os inls.c -c
0.041s
+ gcc -xc++ -Os macs.c -c
0.016s
+ gcc -xc++ -Os incl_vector.cc -c
0.188s
+ gcc -xc++ -Os incl_string.cc -c
0.290s
+ gcc -xc++ -Os incl_iostream.cc -c
0.408s
и очень похожие цифры и относительные различия для лязга.
Прошло много времени с тех пор, как я играл с этим, но IIRC, компиляция C++ была в основном затруднена из-за огромных включаемых файлов STL, а не из-за того, что C++ был намного медленнее (хотя это было немного медленнее, понятное дело) .