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?


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.


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.


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.


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


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ć.


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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.