Clang vs GCC für mein Linux-Entwicklungsprojekt

175

Ich bin im College und für ein Projekt verwenden wir C. Wir haben GCC und Clang untersucht, und Clang scheint viel benutzerfreundlicher zu sein als GCC. Infolgedessen frage ich mich, welche Vor- oder Nachteile die Verwendung von clang im Gegensatz zu GCC für die Entwicklung in C und C ++ unter Linux hat.

In meinem Fall würde dies für Programme auf Studentenebene verwendet, nicht für die Produktion.

Wenn ich Clang verwende, sollte ich mit GDB debuggen und GNU Make verwenden oder einen anderen Debugger und das Dienstprogramm make verwenden?

Haziz
quelle
7
Soweit ich das beurteilen kann, ist Clang noch lange nicht "ausgereift", insbesondere was die Unterstützung von Standardbibliotheken betrifft. Trotzdem hat es fantastische Fehlermeldungen, so dass Sie sich immer einem mysteriösen Compilerfehler nähern können, indem Sie den Code auf Clang ausprobieren. Ich glaube, Clang kann auch C ++ zu C kompilieren.
Kerrek SB
3
@KerrekSB: Welches Element der "Standardbibliotheksunterstützung" fehlt in clang?
Stephen Canon
2
@StephenCanon: Als ich es das letzte Mal ausprobiert habe, musste ich libstdc ++ verwenden (was meines Wissens nicht Teil von Clang ist). Und erst neulich hatten wir dieses Problem . Wie auch immer, ich folge nicht der Blutungskante, daher ist meine Ansicht möglicherweise völlig veraltet.
Kerrek SB
4
@ KerrekSB: In Bezug auf Ihren Link funktioniert Clang nicht unter reinem Windows. Es funktioniert jedoch in MinGW. In Bezug auf die Standardbibliothek gibt es derzeit keinen echten Standardbibliotheksteil von Clang. Clang wird unter OSX mit libc ++ gebündelt, jedoch ist libc ++ in anderen Umgebungen nicht vollständig portiert. Daher muss Clang in diesen Umgebungen eine andere Standardbibliotheksimplementierung installieren. Unter Linux funktioniert libstdc ++.
Matthieu M.
1
@ KerrekSB: C ++ 98 wird zu 100% unterstützt. C ++ 11 wird größtenteils unterstützt (zuletzt habe ich überprüft, <atomic>wird nicht unterstützt, vielleicht fehlen einige andere kleine Dinge ... Ich kann es nicht verwenden, daher bin ich nicht ganz auf dem neuesten Stand).
James McNellis

Antworten:

122

BEARBEITEN:

Die gcc-Leute haben die Diagnoseerfahrung in gcc (ah Wettbewerb) wirklich verbessert. Sie haben eine Wiki-Seite erstellt, um sie hier zu präsentieren . gcc 4.8 hat jetzt auch eine recht gute Diagnose (gcc 4.9x hat Farbunterstützung hinzugefügt). Clang liegt immer noch an der Spitze, aber die Lücke schließt sich.


Original:

Für Studenten würde ich Clang bedingungslos empfehlen.

Die Leistung in Bezug auf den generierten Code zwischen gcc und Clang ist jetzt unklar (obwohl ich denke, dass gcc 4.7 immer noch die Führung hat, habe ich noch keine schlüssigen Benchmarks gesehen), aber für die Schüler ist es sowieso nicht wirklich wichtig, zu lernen.

Auf der anderen Seite ist Clangs äußerst klare Diagnose für Anfänger definitiv leichter zu interpretieren.

Betrachten Sie dieses einfache Snippet:

#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";
}

Sie werden sofort feststellen, dass das Semikolon nach der Definition der StudentKlasse fehlt , oder :)?

Nun, gcc bemerkt es auch auf eine Art und Weise:

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>]

Und Clang spielt auch hier nicht gerade die Hauptrolle, aber dennoch:

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

Ich wähle absichtlich ein Beispiel, das eine unklare Fehlermeldung auslöst (aufgrund einer Mehrdeutigkeit in der Grammatik), anstatt der typischen Beispiele "Oh mein Gott Clang, lies meine Gedanken". Trotzdem stellen wir fest, dass Clang die Flut von Fehlern vermeidet. Keine Notwendigkeit, Schüler abzuschrecken.

Matthieu M.
quelle
2
Ähm ... als ich das letzte Mal nachgesehen habe, habe ich einen Artikel gelesen, in dem verschiedene Benchmarks veröffentlicht wurden, in denen Clang in jedem Test so ziemlich gcc aus dem Wasser geblasen hat. Quelle: clang.llvm.org/features.html#performance
31
@AscensionSystems: Vorsicht, diese Tests zeigen die Leistung der Clang-Binärdatei selbst (und das war vor einiger Zeit), nicht die Leistung der von Ihnen kompilierten Binärdatei.
Matthieu M.
Das ist ein guter Punkt. Ich würde mich für einen Stand-up-Vergleich zwischen den kompilierten ausführbaren Dateien interessieren. Ich habe den Eindruck, dass Clang bei der Optimierung viel bessere Arbeit leistet, aber ich habe tatsächlich keine Benchmarks gesehen. Ich werde das überprüfen.
4
@AscensionSystems: Hier ist die neueste Bank, die mir bekannt ist , wenn ich gcc 4.6 mit llvm 3.0 vergleiche, was einen Nettovorteil von gcc im Durchschnitt zeigt. Interessant ist möglicherweise auch die DragonEgg-Bank . DragonEgg ist ein Plugin, mit dem das gcc-Frontend (und möglicherweise der Optimierer) und anschließend das LLVM-Backend zum Generieren des Codes verwendet werden können.
Matthieu M.
1
Als ich das letzte Mal nachgesehen habe, waren Phoronix-Benchmarks sehr unzuverlässig: Compiler-Flags wurden nicht richtig dokumentiert, aber die Ergebnisse deuteten darauf hin, dass die Dinge nicht richtig gesetzt wurden.
Eamon Nerbonne
35

Ab sofort bietet GCC eine viel bessere und umfassendere Unterstützung für C ++ 11-Funktionen als Clang. Außerdem führt der Codegenerator für GCC eine bessere Optimierung durch als der in Clang (meiner Erfahrung nach habe ich keine erschöpfenden Tests gesehen).

Andererseits kompiliert Clang Code häufig schneller als GCC und erzeugt bessere Fehlermeldungen, wenn etwas mit Ihrem Code nicht stimmt.

Die Wahl, welche Sie verwenden möchten, hängt wirklich davon ab, welche Dinge für Sie wichtig sind. Ich schätze die Unterstützung von C ++ 11 und die Qualität der Codegenerierung mehr als die Bequemlichkeit der Kompilierung. Aus diesem Grund benutze ich GCC. Für Sie könnten die Kompromisse unterschiedlich sein.

Mankarse
quelle
3
Hier ist der neueste Phoronix-Artikel zum Vergleich von GCC 4.6 mit Clang 3.0 sowie ein vorheriger Artikel speziell für die Bulldozer-Plattform. Abhängig von den Benchmarks ist der Gewinner entweder der eine oder der andere (im vorherigen Artikel erscheint auch gcc 4.7), daher finde ich persönlich unklar, welche besser abschneidet.
Matthieu M.
Warum nicht beides verwenden? Clang für die Entwicklung und GCC für die Produktion.
Segfault
5
@segfault: Das ist was ich gerade mache. Diese Antwort ist ziemlich alt und nicht mehr ganz richtig. Sowohl Clang als auch GCC haben sich seit meinem Schreiben erheblich verbessert (insbesondere entspricht Clang jetzt der allgemeinen C ++ 11-Unterstützung von GCC, und GCC hat seine Fehlermeldungen und die Kompilierungsgeschwindigkeit verbessert). Jetzt würde ich vorschlagen, beide zu verwenden, mit einer leichten Präferenz gegenüber Clang, da der Clang-Quellcode viel einfacher zu verstehen ist als die GCC-Quelle.
Mankarse
23

Ich benutze beide, weil sie manchmal unterschiedliche, nützliche Fehlermeldungen geben.

Das Python-Projekt konnte eine Reihe kleiner Fehler finden und beheben, als einer der Kernentwickler zum ersten Mal versuchte, mit clang zu kompilieren.

Raymond Hettinger
quelle
1
Was halten Sie von Clang für Debug-Builds, aber von gcc für optimierte Releases?
Olical
5
Es ist vernünftig, mit Clang zu entwickeln und mit GCC zu veröffentlichen, aber stellen Sie sicher, dass Ihre GCC-Version Ihre Testsuite besteht (sowohl mit als auch ohne NDEBUG).
Raymond Hettinger
2
Danke für die Antwort. Ich habe es ein bisschen ausprobiert und es funktioniert wirklich gut. Ich bekomme auch verschiedene Warnungen, was großartig ist.
Olical
11

Ich verwende sowohl Clang als auch GCC. Ich finde, Clang hat einige nützliche Warnungen, aber für meine eigenen Raytracing-Benchmarks - es ist durchweg 5-15% langsamer als GCC (nimm das natürlich mit Salzkorn, habe aber versucht, ähnliche Optimierungsflags zu verwenden für beide).

Daher verwende ich vorerst die statische Analyse von Clang und ihre Warnungen mit komplexen Makros: (obwohl die Warnungen von GCC jetzt ziemlich gut sind - gcc4.8 - 4.9).

Einige Überlegungen:

  • Clang hat keine OpenMP-Unterstützung, ist nur wichtig, wenn Sie dies nutzen, aber da ich dies tue, ist dies eine Einschränkung für mich. (*****)
  • Cross Compilation wird möglicherweise nicht so gut unterstützt (FreeBSD 10 verwendet beispielsweise immer noch GCC4.x für ARM), gcc-mingw ist beispielsweise unter Linux verfügbar ... (YMMV).
  • Einige IDEs unterstützen das Parsen der Clangs-Ausgabe noch nicht ( QtCreator zum Beispiel *****). BEARBEITEN: QtCreator unterstützt jetzt die Ausgabe von Clang
  • Einige Aspekte von GCC sind besser dokumentiert. Da es GCC schon länger gibt und weit verbreitet ist, ist es möglicherweise einfacher, Hilfe bei Warnungen / Fehlermeldungen zu erhalten.

***** - Diese Bereiche befinden sich in aktiver Entwicklung und werden möglicherweise bald unterstützt

ideasman42
quelle
Ich benutze auch OpenMP, aber ich denke darüber nach, zu TBB zu wechseln, was meiner Meinung nach mit Clang funktionieren würde.
1
TBB kann in einigen Fällen eine praktikable Alternative für OpenMP sein (aber soweit ich das beurteilen kann nur für C ++), für C wird es nicht unterstützt - auch für große Projekte lohnt es sich möglicherweise nicht, von OpenMP zu etwas anderem zu wechseln, insbesondere wenn Clang es irgendwann tun wird unterstützt OpenMP trotzdem.
ideasman42
7

Für Programme auf Studentenebene hat Clang den Vorteil, dass es standardmäßig strenger ist. der C-Standard. Beispielsweise wird die folgende K & R-Version von Hello World von GCC ohne Vorwarnung akzeptiert, von Clang jedoch mit einigen ziemlich beschreibenden Fehlermeldungen abgelehnt:

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

Bei GCC müssen Sie es geben -Werror, damit es wirklich darauf hinweist , dass es sich nicht um ein gültiges C89-Programm handelt. Außerdem müssen Sie noch die Sprache C99 verwenden c99oder gcc -std=c99herunterladen.

Fred Foo
quelle
8
gccsollte im Allgemeinen mit mindestens aufgerufen werden -Wall, was für dieses Programm warnt. clangerzeugt jedoch gute Warnungen / Fehler.
Café
2
@caf: Das ist genau der Punkt, den ich versuche, mit GCC müssen Sie es Optionen übergeben. Nach dem Auspacken ist es möglicherweise zu tolerant für Unterrichtszwecke.
Fred Foo
Das mag wahr sein, aber es ist ein ziemlich kleiner Punkt. Wichtiger ist die Qualität der Fehlermeldungen. GCC 4.6 ist ziemlich gut geworden, obwohl ich verstehe, dass Clang dort echte Magie ausübt.
Kerrek SB
2
@dreamlax: True; es gibt auch gnu99und gnu++98und gnu++0x. Ich denke, das sind echte Erweiterungen , dh sie kompilieren problemlos den ISO-Standardcode. Hier sind die Details: für C , für C ++ .
Kerrek SB
1
Dieses Programm sollte keine Fehler oder Warnungen erzeugen. Es entspricht dem Standard.
Miles Rout
3

Ich denke, Clang könnte eine Alternative sein.

GCC und Clang haben einige Unterschiede in Bezug auf Ausdrücke wie a+++++a, und ich habe viele verschiedene Antworten mit meinem Kollegen, der Clang auf dem Mac verwendet, während ich gcc verwende.

GCC ist zum Standard geworden, und Clang könnte eine Alternative sein. Weil GCC sehr stabil ist und Clang sich noch in der Entwicklung befindet.

Songziming
quelle
5
Clang bereitet sich schnell darauf vor, GCC in der Linux-Welt vollständig zu ersetzen, und hat dies größtenteils in der BSD-Welt getan. Es hat GCC vor Jahren auf dem Mac ersetzt. Clang ist gutes Zeug. Ich denke, GCC könnte persönlich eine Alternative werden, und ich würde mich darüber freuen.
coder543
5
Der Ausdruck a +++++ a ist undefiniert. Erwarten Sie daher, dass Sie auf jedem Compiler oder sogar auf verschiedenen Versionen desselben Compilers eine andere Antwort erhalten. Sie können sogar unterschiedliche Ergebnisse für diesen Ausdruck auf demselben Compiler erhalten, wenn Sie zu unterschiedlichen Zeiten kompiliert werden. Das bedeutet "undefiniert".
Lelanthran
1
a+++++asollte fehlschlagen, da es als a ++ ++ + aSyntaxfehler analysiert wird.
Miles Rout
@Lelanthran das ist nicht was undefiniert bedeutet. Es hat ein undefiniertes Verhalten, so dass der Compiler das nicht kompilieren kann, oder es kann zur Laufzeit auslösen oder die CPU sperren, so dass Sie einen Hard-Reset oder etwas noch Unheimlicheres durchführen müssen.
Antti Haapala