Clang vs GCC for my Linux Development project

114,198

Solution 1

EDIT:

The gcc guys really improved the diagnosis experience in gcc (ah competition). They created a wiki page to showcase it here. gcc 4.8 now has quite good diagnostics as well (gcc 4.9x added color support). Clang is still in the lead, but the gap is closing.


Original:

For students, I would unconditionally recommend Clang.

The performance in terms of generated code between gcc and Clang is now unclear (though I think that gcc 4.7 still has the lead, I haven't seen conclusive benchmarks yet), but for students to learn it does not really matter anyway.

On the other hand, Clang's extremely clear diagnostics are definitely easier for beginners to interpret.

Consider this simple 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";
}

You'll notice right away that the semi-colon is missing after the definition of the Student class, right :) ?

Well, gcc notices it too, after a fashion:

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

And Clang is not exactly starring here either, but still:

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

I purposefully choose an example which triggers an unclear error message (coming from an ambiguity in the grammar) rather than the typical "Oh my god Clang read my mind" examples. Still, we notice that Clang avoids the flood of errors. No need to scare students away.

Solution 2

As of right now, GCC has much better and more complete support for C++11 features than Clang. Also, the code generator for GCC performs better optimisation than the one in Clang (in my experience, I have not seen any exhaustive tests).

On the other hand, Clang often compiles code more quickly than GCC, and produces better error messages when there is something wrong with your code.

The choice of which one to use really depends on what things are important to you. I value C++11 support and code generation quality more than I value convenience of compilation. Because of this, I use GCC. For you, the trade-offs could be different.

Solution 3

I use both because sometimes they give different, useful error messages.

The Python project was able to find and fix a number of small buglets when one of the core developers first tried compiling with clang.

Solution 4

I use both Clang and GCC, I find Clang has some useful warnings, but for my own ray-tracing benchmarks - its consistently 5-15% slower then GCC (take that with grain of salt of course, but attempted to use similar optimization flags for both).

So for now I use Clang static analysis and its warnings with complex macros: (though now GCC's warnings are pretty much as good - gcc4.8 - 4.9).

Some considerations:

  • Clang has no OpenMP support, only matters if you take advantage of that but since I do, its a limitation for me. (*****)
  • Cross compilation may not be as well supported (FreeBSD 10 for example still use GCC4.x for ARM), gcc-mingw for example is available on Linux... (YMMV).
  • Some IDE's don't yet support parsing Clangs output (QtCreator for example *****). EDIT: QtCreator now supports Clang's output
  • Some aspects of GCC are better documented and since GCC has been around for longer and is widely used, you might find it easier to get help with warnings / error messages.

***** - these areas are in active development and may soon be supported

Solution 5

For student level programs, Clang has the benefit that it is, by default, stricter wrt. the C standard. For example, the following K&R version of Hello World is accepted without warning by GCC, but rejected by Clang with some pretty descriptive error messages:

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

With GCC, you have to give it -Werror to get it to really make a point about this not being a valid C89 program. Also, you still need to use c99 or gcc -std=c99 to get the C99 language.

Share:
114,198

Related videos on Youtube

haziz
Author by

haziz

Updated on December 30, 2020

Comments

  • haziz
    haziz over 3 years

    I'm in college, and for a project we're using C. We've explored GCC and Clang, and Clang appears to be much more user friendly than GCC. As a result, I'm wondering what the advantages or disadvantages are to using clang, as opposed to GCC, for developing in C and C++ on Linux?

    In my case this would be used for student level programs, not production.

    If I use Clang, should I debug with GDB and use GNU Make, or use another debugger and make utility?

    • Kerrek SB
      Kerrek SB over 12 years
      As far as I can tell, Clang is still far from "mature", especially concerning standard library support. Nonetheless, it has fantastic error messages, so you can always approach a mysterious compiler error by trying the code on Clang. Clang can also compile C++ to C, I believe.
    • Stephen Canon
      Stephen Canon over 12 years
      @KerrekSB: what element of "standard library support" is missing from clang?
    • Kerrek SB
      Kerrek SB over 12 years
      @StephenCanon: Last time I tried it, I had to use libstdc++ (which isn't part of Clang as far as I understand). And just the other day we had this issue. Anyway, I'm not following the bleeding edge, so my view may be entirely obsolete.
    • Matthieu M.
      Matthieu M. over 12 years
      @KerrekSB: Regarding your link, Clang does not work on pure Windows. It works in MinGW though. Regarding the standard library, there is no real standard library part of Clang at the moment. Clang is bundled with libc++ on OSX, however libc++ is not fully ported in other environments, so on those Clang need another Standard Library implementation to be installed. On Linux, libstdc++ works.
    • Kerrek SB
      Kerrek SB over 12 years
      @MatthieuM.: How complete is libc++?
    • James McNellis
      James McNellis over 12 years
      @KerrekSB: C++98 is 100% supported. C++11 is mostly supported (last I checked, <atomic> is not supported, perhaps some other small things are missing... I can't use it, so I'm not entirely up to speed with it).
    • James McNellis
      James McNellis over 12 years
      @MatthieuM.: You can build clang with VC10. You can't use clang to compile code using the VC10 Standard Library, though (among other reasons, the VC10 headers rely on many VC implementation details... reasonably so).
    • Matthieu M.
      Matthieu M. over 12 years
      @JamesMcNellis: to be fair, I think that <atomic> is not complete on libstdc++ either. The last discussion I saw on the Clang mailing list (with the participation of one of the gcc dev) implied that things were not totally decided on the low-level facilities to be provided to write those atomics.
    • Matthieu M.
      Matthieu M. over 12 years
      @JamesMcNellis: Sorry if I was unclear. I was indeed speaking of generating VC++ compatible code.
    • rubenvb
      rubenvb almost 11 years
      The answers to this question will always be horribly out of date.
  • caf
    caf over 12 years
    gcc should generally be invoked with at least -Wall, which does warn for this program. clang does produce good warnings/errors, though.
  • Fred Foo
    Fred Foo over 12 years
    @caf: which is exactly the point I'm trying to make, with GCC you have to pass it options. Out of the box, it may be too tolerant for teaching purposes.
  • Kerrek SB
    Kerrek SB over 12 years
    That may be true, but it's a fairly minor point. What's more important is the quality of the error messages. GCC 4.6 has got pretty good, though I understand that clang is doing some real magic there.
  • TOMKA
    TOMKA over 12 years
    I think GCC used to (not sure if it still does) default to its own dialect of the C language called gnu89, which is C89 plus a few features GNU put in (some of which are found in C99).
  • Matthieu M.
    Matthieu M. over 12 years
    Here is the latest Phoronix article comparing GCC 4.6 vs Clang 3.0 as well as a previous article specific to the bulldozer platform. Depending on the benchmarks, the winner is either one or the other (on the previous article, gcc 4.7 appears too), so I personally find it unclear which is performing better.
  • Kerrek SB
    Kerrek SB over 12 years
    @dreamlax: True; there's also gnu99, and gnu++98 and gnu++0x. I think those are genuine extensions, though, i.e. they will compile conforming ISO-standard code without a hitch. Here are the details: for C, for C++.
  • Admin
    Admin over 12 years
    Um... last time I checked I read an article that published various benchmarks where clang pretty much blew gcc out of the water in ever test. Source: clang.llvm.org/features.html#performance
  • Matthieu M.
    Matthieu M. over 12 years
    @AscensionSystems: beware, those tests show the performance of the Clang binary itself (and that was a while ago), not the performance of the binary you were compiling.
  • Admin
    Admin over 12 years
    That's a good point I'd be interested to see a stand up comparison between the compiled executables. I'm under the impression that clang does a much better job at optimization but I havn't actually seen any benchmarks. I'll check it out.
  • Admin
    Admin over 12 years
    Most recent benchmarks done are showing that there is no one compiler which is overall better than the other. In some tests one dominates the other and vise versa, but these instances are pretty evenly split. Link: phoronix.com/…
  • Matthieu M.
    Matthieu M. over 12 years
    @AscensionSystems: here is the latest bench I am aware of comparing gcc 4.6 to llvm 3.0 which shows a net advantage of gcc in average. Also interesting may be the DragonEgg bench, DragonEgg is a plugin that allows using the gcc front-end (and possibly optimizer) and then the LLVM backend to generate the code.
  • Eamon Nerbonne
    Eamon Nerbonne about 12 years
    Last time I checked, phoronix benchmarks were very untrustworthy: compiler flags weren't properly documented, but the results suggested things weren't being set properly.
  • Matthieu M.
    Matthieu M. about 12 years
    @EamonNerbonne: still they are one of the few benchmarks available. Of interest to you may be a benchmark by the Chromium team with recent versions of both clang and gcc. Although it is only the build time.
  • Eamon Nerbonne
    Eamon Nerbonne about 12 years
    Good find! I also came across these SPEC benchmark runs: vmakarov.fedorapeople.org/spec/2011/llvmgcc32.html and vmakarov.fedorapeople.org/spec/2011/llvmgcc64.html. vmakarov.fedorapeople.org/spec also has some older results.
  • Matthieu M.
    Matthieu M. about 12 years
    @EamonNerbonne: very nice, it would be great if we had the same benchmarks for llvm 3.0 / gcc 4.6.
  • Olical
    Olical over 11 years
    What are your thoughts on using clang for debug builds but gcc for optimised releases?
  • Raymond Hettinger
    Raymond Hettinger over 11 years
    It's reasonable to develop with Clang and release with GCC, but be sure your GCC release passes your test suite (both with and without NDEBUG).
  • Olical
    Olical over 11 years
    Thanks for the response. I have been trying it out for a bit and it works really well. I get different sets of warnings too, which is great.
  • segfault
    segfault over 11 years
    Why not use both? Clang for development, and GCC for production.
  • Mankarse
    Mankarse over 11 years
    @segfault: That is what I am doing currently. This answer is quite old, and it is no longer entirely true. Both Clang and GCC have improved significantly since I wrote it (in particular, Clang now matches GCC overall C++11 support, and GCC has improved its error messages and compilation speed). Now I would suggest using both, with a slight preference towards Clang because the Clang source code is a lot easier to understand than the GCC source.
  • Miles Rout
    Miles Rout over 11 years
    This program shouldn't produce errors or warnings. It conforms to the standard.
  • haziz
    haziz about 11 years
    With the release of GCC 4.8, I wonder how the competition in clarity of error messages and warnings now stacks up?
  • Matthieu M.
    Matthieu M. about 11 years
    @haziz: I wish I knew too, according to gcc they do much better than they used to, but then Clang is also improving (notably with an algorithm to compute (and print) a diff between two template types), and neither side has made updates.
  • Admin
    Admin almost 11 years
    I use OpenMP as well but I am thinking of switching to TBB which I guess would work with Clang.
  • coder543
    coder543 almost 11 years
    Clang is rapidly preparing to replace GCC completely in the Linux world, and has largely done so in the BSD world. It replaced GCC on Mac years ago. Clang is good stuff. I think GCC could become an alternative, personally, and I would happy about that.
  • ideasman42
    ideasman42 over 10 years
    TBB may be a viable alternative for OpenMP in some cases (but only for C++ as far as I can tell), for C its not supported - also for large projects, switching from OpenMP to something else might not be worthwhile especially if Clang will eventually support OpenMP anyway.
  • Lelanthran
    Lelanthran about 10 years
    The expression a+++++a is undefined so expect to get a different answer on each compiler, or even on different versions of the same compiler. You could even get different results for that expression on the same compiler when compiled at different times. That's what "undefined" means.
  • Etherealone
    Etherealone almost 10 years
    @MilesRout Not for C++ afaik.
  • Miles Rout
    Miles Rout almost 10 years
    Indeed true, C, not C++.
  • Miles Rout
    Miles Rout almost 10 years
    a+++++a should fail, as it's parsed as a ++ ++ + a which is a syntax error.
  • Matthieu M.
    Matthieu M. over 8 years
    @ideasman42: I just saw your edit, it amused me because looking at the revision history, you were the one adding this "available in gcc 4.9" bit nearly 2 years ago! In any case, thanks for polishing this answer.
  • Rahly
    Rahly almost 7 years
    Good to note that GCC's c++ default to C++14 in version 6.1 or higher
  • Antti Haapala -- Слава Україні
    Antti Haapala -- Слава Україні over 6 years
    @MilesRout it doesn't conform to the standard. It conforms to an old revoked edition of the standard. You wouldn't say "this is legal" about something that only conforms to laws of 18th century either...
  • Antti Haapala -- Слава Україні
    Antti Haapala -- Слава Україні over 6 years
    @Lelanthran that is not what undefined means. It has undefined behaviour so the compiler can fail to compile that, or it can throw at runtime or lock the CPU so that you need to do hard reset or something even more sinister.