Clang vs GCC dla mojego projektu Linux Development

175

Jestem na studiach i do projektu używamy C. Zbadaliśmy GCC i Clang, i Clang wydaje się być znacznie bardziej przyjazny dla użytkownika niż GCC. W rezultacie zastanawiam się, jakie są zalety i wady używania clang, w przeciwieństwie do GCC, do programowania w C i C ++ na Linuksie?

W moim przypadku byłoby to używane do programów na poziomie studenckim, a nie do produkcji.

Jeśli używam Clang, czy powinienem debugować za pomocą GDB i używać GNU Make, czy może użyć innego debuggera i narzędzia make?

haziz
źródło
7
O ile wiem, Clang wciąż jest daleki od „dojrzałości”, zwłaszcza jeśli chodzi o obsługę standardowej biblioteki. Niemniej jednak ma fantastyczne komunikaty o błędach, więc zawsze możesz podejść do tajemniczego błędu kompilatora, wypróbowując kod na Clang. Uważam, że Clang może również skompilować C ++ do C.
Kerrek SB
3
@KerrekSB: jakiego elementu „obsługi bibliotek standardowych” brakuje w clang?
Stephen Canon
2
@StephenCanon: Kiedy ostatnio tego próbowałem, musiałem użyć libstdc ++ (co nie jest częścią Clang, o ile rozumiem). Niedawno mieliśmy ten problem . W każdym razie nie podążam za krwawiącą krawędzią, więc mój pogląd może być całkowicie przestarzały.
Kerrek SB
4
@KerrekSB: Jeśli chodzi o twoje łącze, Clang nie działa w czystym systemie Windows. Działa jednak w MinGW. Jeśli chodzi o bibliotekę standardową, w tej chwili nie ma prawdziwej części biblioteki standardowej Clang. Clang jest dołączony do libc ++ na OSX, jednak libc ++ nie jest w pełni przeniesiony w innych środowiskach, więc w tych Clang wymaga zainstalowania innej implementacji biblioteki standardowej. W systemie Linux działa libstdc ++.
Matthieu M.,
1
@KerrekSB: C ++ 98 jest w 100% obsługiwany. C ++ 11 jest w większości obsługiwany (ostatnio sprawdzałem, <atomic>nie jest obsługiwany, być może brakuje kilku innych drobiazgów ... Nie mogę go używać, więc nie jestem do końca na bieżąco z tym).
James McNellis

Odpowiedzi:

122

EDYTOWAĆ:

Faceci z gcc naprawdę poprawili jakość diagnozy w gcc (konkurs ah). Stworzyli stronę wiki, aby zaprezentować ją tutaj . gcc 4.8 ma teraz całkiem dobrą diagnostykę (dodano obsługę kolorów w gcc 4.9x). Clang nadal prowadzi, ale różnica się zmniejsza.


Oryginalny:

Studentom bezwarunkowo poleciłbym Clang.

Wydajność pod względem wygenerowanego kodu między gcc i Clang jest teraz niejasna (chociaż myślę, że gcc 4.7 nadal ma przewagę, nie widziałem jeszcze rozstrzygających testów porównawczych), ale uczenie się przez uczniów i tak nie ma tak naprawdę znaczenia.

Z drugiej strony niezwykle przejrzysta diagnostyka Clanga jest zdecydowanie łatwiejsza do interpretacji dla początkujących.

Rozważ ten prosty fragment:

#include <string>
#include <iostream>

struct Student {
std::string surname;
std::string givenname;
}

std::ostream& operator<<(std::ostream& out, Student const& s) {
  return out << "{" << s.surname << ", " << s.givenname << "}";
}

int main() {
  Student me = { "Doe", "John" };
  std::cout << me << "\n";
}

Od razu zauważysz, że po definicji Studentklasy brakuje średnika , prawda :)?

Cóż, gcc też to zauważa , po pewnym czasie:

prog.cpp:9: error: expected initializer before ‘&’ token
prog.cpp: In function int main()’:
prog.cpp:15: error: no match for operator<<’ in std::cout << me
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:112: note: candidates are: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>& (*)(std::basic_ostream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:121: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ios<_CharT, _Traits>& (*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:131: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:169: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:173: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:177: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/ostream.tcc:97: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:184: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/ostream.tcc:111: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:195: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:204: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:208: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:213: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:217: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:225: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/ostream:229: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/ostream.tcc:125: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_streambuf<_CharT, _Traits>*) [with _CharT = char, _Traits = std::char_traits<char>]

Clang też nie występuje tutaj, ale nadal:

/tmp/webcompile/_25327_1.cc:9:6: error: redefinition of 'ostream' as different kind of symbol
std::ostream& operator<<(std::ostream& out, Student const& s) {
     ^
In file included from /tmp/webcompile/_25327_1.cc:1:
In file included from /usr/include/c++/4.3/string:49:
In file included from /usr/include/c++/4.3/bits/localefwd.h:47:
/usr/include/c++/4.3/iosfwd:134:33: note: previous definition is here
  typedef basic_ostream<char>           ostream;        ///< @isiosfwd
                                        ^
/tmp/webcompile/_25327_1.cc:9:13: error: expected ';' after top level declarator
std::ostream& operator<<(std::ostream& out, Student const& s) {
            ^
            ;
2 errors generated.

Celowo wybieram przykład, który wywołuje niejasny komunikat o błędzie (wynikający z niejasności w gramatyce), zamiast typowych przykładów „O mój Boże Clang, przeczytaj mi w myślach”. Mimo to zauważamy, że Clang unika zalewu błędów. Nie musisz odstraszać uczniów.

Matthieu M.
źródło
2
Um ... ostatnim razem, gdy sprawdzałem, przeczytałem artykuł, który opublikował różne testy porównawcze, w których clang prawie wysadził gcc z wody w każdym teście. Źródło: clang.llvm.org/features.html#performance
31
@AscensionSystems: uwaga, te testy pokazują wydajność samego pliku binarnego Clang (a to było jakiś czas temu), a nie wydajności binarnego, który kompilowałeś.
Matthieu M.
To dobra uwaga, chciałbym zobaczyć porównanie między skompilowanymi plikami wykonywalnymi. Mam wrażenie, że clang znacznie lepiej radzi sobie z optymalizacją, ale tak naprawdę nie widziałem żadnych testów porównawczych. Sprawdzę to.
4
@AscensionSystems: oto najnowsza ławka, jaką znam, porównując gcc 4.6 z llvm 3.0, która pokazuje średnią przewagę netto gcc. Interesująca może być także ławka DragonEgg , DragonEgg to wtyczka, która umożliwia użycie front-endu gcc (i prawdopodobnie optymalizatora), a następnie zaplecza LLVM do generowania kodu.
Matthieu M.
1
Ostatnim razem, gdy sprawdzałem, testy porównawcze phoronix były bardzo niewiarygodne: flagi kompilatora nie były odpowiednio udokumentowane, ale wyniki sugerowały, że rzeczy nie zostały poprawnie ustawione.
Eamon Nerbonne,
35

W tej chwili GCC ma znacznie lepsze i pełniejsze wsparcie dla funkcji C ++ 11 niż Clang. Ponadto generator kodu dla GCC zapewnia lepszą optymalizację niż ten w Clang (z mojego doświadczenia nie widziałem żadnych wyczerpujących testów).

Z drugiej strony Clang często kompiluje kod szybciej niż GCC i generuje lepsze komunikaty o błędach, gdy coś jest nie tak z kodem.

Wybór, którego użyć, naprawdę zależy od tego, jakie rzeczy są dla Ciebie ważne. Bardziej cenię obsługę języka C ++ 11 i jakość generowania kodu niż wygodę kompilacji. Z tego powodu używam GCC. Dla Ciebie kompromisy mogą być inne.

Mankarse
źródło
3
Oto najnowszy artykuł Phoronix porównujący GCC 4.6 z Clang 3.0, a także poprzedni artykuł dotyczący platformy buldożera. W zależności od benchmarków, zwycięzcą jest jeden lub drugi (w poprzednim artykule pojawia się również gcc 4.7), więc osobiście nie jest jasne, które działa lepiej.
Matthieu M.
Dlaczego nie użyć obu? Clang do rozwoju i GCC do produkcji.
segfault
5
@segfault: To właśnie teraz robię. Ta odpowiedź jest dość stara i nie jest już do końca prawdziwa. Zarówno Clang, jak i GCC uległy znacznej poprawie od czasu, gdy go napisałem (w szczególności Clang jest teraz zgodny z ogólną obsługą C ++ 11 w GCC, a GCC poprawił komunikaty o błędach i szybkość kompilacji). Teraz sugerowałbym użycie obu, z niewielką preferencją w stosunku do Clang, ponieważ kod źródłowy Clang jest dużo łatwiejszy do zrozumienia niż źródło GCC.
Mankarse
23

Używam obu, ponieważ czasami podają różne, przydatne komunikaty o błędach.

Projekt Python był w stanie znaleźć i naprawić wiele małych bugletów, gdy jeden z głównych programistów po raz pierwszy próbował kompilować za pomocą clang.

Raymond Hettinger
źródło
1
Co myślisz o używaniu Clang do debugowania kompilacji, ale gcc do zoptymalizowanych wydań?
Olical
5
Rozsądne jest programowanie z Clang i wydawanie z GCC, ale upewnij się, że Twoje wydanie GCC przejdzie twój zestaw testów (zarówno z, jak i bez NDEBUG).
Raymond Hettinger
2
Dzięki za odpowiedzi. Wypróbowałem to już od jakiegoś czasu i działa naprawdę dobrze. Dostaję też różne zestawy ostrzeżeń, co jest świetne.
Olical
11

Używam zarówno Clang, jak i GCC, uważam, że Clang ma kilka przydatnych ostrzeżeń, ale dla moich własnych testów wzorcowych śledzenia promieni - jest konsekwentnie o 5-15% wolniejszy niż GCC (oczywiście z przymrużeniem oka, ale próbowałem użyć podobnych flag optymalizacji dla obu).

Więc na razie używam analizy statycznej Clang i jej ostrzeżeń ze złożonymi makrami: (chociaż teraz ostrzeżenia GCC są tak samo dobre - gcc4.8 - 4.9).

Kilka uwag:

  • Clang nie obsługuje OpenMP, ma znaczenie tylko wtedy, gdy z tego skorzystasz, ale ponieważ to robię, jest to dla mnie ograniczenie. (*****)
  • Kompilacja krzyżowa może nie być tak dobrze obsługiwana (na przykład FreeBSD 10 nadal używa GCC4.x dla ARM), na przykład gcc-mingw jest dostępny na Linuksie ... (YMMV).
  • Niektóre IDE nie obsługują jeszcze przetwarzania danych wyjściowych Clangs ( na przykład QtCreator *****). EDYCJA: QtCreator obsługuje teraz wyjście Clang
  • Niektóre aspekty GCC są lepiej udokumentowane, a ponieważ GCC istnieje od dłuższego czasu i jest szeroko używane, może być łatwiej uzyskać pomoc dotyczącą ostrzeżeń / komunikatów o błędach.

***** - te obszary są aktywnie rozwijane i mogą wkrótce otrzymać wsparcie

ideasman42
źródło
Używam również OpenMP, ale myślę o przejściu na TBB, który, jak sądzę, działałby z Clangiem.
1
TBB może być realną alternatywą dla OpenMP w niektórych przypadkach (ale tylko dla C ++, o ile wiem), dla C nie jest obsługiwany - również w przypadku dużych projektów, przejście z OpenMP na coś innego może nie być opłacalne, zwłaszcza jeśli Clang w końcu to zrobi i tak obsługują OpenMP.
ideasman42
7

W przypadku programów dla studentów Clang ma tę zaletę, że jest domyślnie bardziej rygorystyczny. standard C. Na przykład następująca wersja Hello World K&R jest akceptowana bez ostrzeżenia przez GCC, ale odrzucana przez Clang z kilkoma dość opisowymi komunikatami o błędach:

main()
{
    puts("Hello, world!");
}

W przypadku GCC musisz dać to -Werror, aby naprawdę zwrócić uwagę na to, że nie jest to poprawny program C89. Ponadto nadal musisz używać języka C99 c99lub gcc -std=c99go pobrać.

Fred Foo
źródło
8
gccpowinno być generalnie wywoływane z co najmniej -Wall, co ostrzega przed tym programem. clangjednak generuje dobre ostrzeżenia / błędy.
kawiarnia
2
@caf: właśnie o to mi chodzi, w przypadku GCC musisz podać opcje. Po wyjęciu z pudełka może być zbyt tolerancyjny do celów dydaktycznych.
Fred Foo
Może to prawda, ale jest to dość drobna kwestia. Ważniejsza jest jakość komunikatów o błędach. GCC 4.6 ma się całkiem nieźle, chociaż rozumiem, że clang robi tam prawdziwą magię.
Kerrek SB
2
@dreamlax: True; jest też gnu99i gnu++98i gnu++0x. Myślę, że są to oryginalne rozszerzenia , tj. Będą kompilować zgodnie ze standardem ISO bez żadnych problemów. Oto szczegóły: dla C , dla C ++ .
Kerrek SB
1
Ten program nie powinien generować błędów ani ostrzeżeń. Jest zgodny ze standardem.
Miles Rout
3

Myślę, że clang może być alternatywą.

GCC i clang mają pewne różnice w wyrażeniach, takich jak a+++++a, i mam wiele różnych odpowiedzi od moich rówieśników, którzy używają clang na Macu, podczas gdy ja używam gcc.

GCC stało się standardem, a clang może być alternatywą. Ponieważ GCC jest bardzo stabilny, a clang wciąż się rozwija.

songziming
źródło
5
Clang szybko przygotowuje się do całkowitego zastąpienia GCC w świecie Linuksa iw dużej mierze zrobił to w świecie BSD. Zastąpił GCC na Macu lata temu. Clang to dobra rzecz. Myślę, że osobiście GCC mogłoby stać się alternatywą i byłbym z tego powodu szczęśliwy.
coder543
5
Wyrażenie a +++++ a jest niezdefiniowane, więc spodziewaj się uzyskania innej odpowiedzi na każdym kompilatorze, a nawet w różnych wersjach tego samego kompilatora. Możesz nawet uzyskać różne wyniki dla tego wyrażenia na tym samym kompilatorze, gdy był on kompilowany w różnym czasie. To właśnie oznacza „nieokreślony”.
Lelanthran
1
a+++++apowinien się nie powieść, ponieważ jest analizowany jako a ++ ++ + abłąd składniowy.
Przebieg mil
@Lelanthran to nie jest to, co znaczy undefined. Ma niezdefiniowane zachowanie, więc kompilator może go nie skompilować lub może rzucić w czasie wykonywania lub zablokować procesor, tak że musisz wykonać twardy reset lub coś jeszcze bardziej złowrogiego.
Antti Haapala