Clang vs GCC用于我的Linux开发项目

haz*_*ziz 168 c c++ linux gcc clang

我在大学,我们正在使用C项目.我们已经探索过GCC和Clang,而Clang似乎比GCC更加用户友好.因此,我想知道使用clang(而不是GCC)在Linux上使用C和C++进行开发有哪些优点或缺点?

在我的情况下,这将用于学生级程序,而不是生产.

如果我使用Clang,我应该使用GDB调试并使用GNU Make,还是使用其他调试器和make实用程序?

Mat*_* M. 113

编辑:

gcc的人真的改善了gcc的诊断经验(比赛啊).他们创建了维基页面来展示它在这里.gcc 4.8现在也具有相当好的诊断功能(gcc 4.9x增加了颜色支持).Clang仍处于领先地位,但差距正在缩小.


原版的:

对于学生,我会无条件地推荐Clang.

gcc和Clang之间生成代码的表现现在还不清楚(虽然我认为gcc 4.7仍然领先,但我还没有看到确凿的基准),但对于学生来说,学习它并不重要.

另一方面,Clang极其清晰的诊断对初学者来说更容易解释.

考虑一下这个简单的片段:

#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";
}
Run Code Online (Sandbox Code Playgroud)

你会立刻注意到在定义Student类之后缺少分号,对吧:)?

好吧,gcc也注意到它,经过时尚:

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>]
Run Code Online (Sandbox Code Playgroud)

而且Clang也不是在这里主演,但仍然:

/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.
Run Code Online (Sandbox Code Playgroud)

我故意选择一个触发不明确错误信息的例子(来自语法中的含糊不清),而不是典型的"哦,我的上帝克朗读我的思想"的例子.尽管如此,我们还是注意到Clang避免了大量的错误.无需吓跑学生.

  • @AscensionSystems:注意,那些测试显示了Clang二进制文件本身的性能(那是前一段时间),而不是你编译的二进制文件的性能. (28认同)
  • @AscensionSystems:这是我所知道的比较[gcc 4.6到llvm 3.0](http://www.phoronix.com/scan.php?page=article&item=llvm3_gcc_open64&num=1)的最新工作台,它显示了gcc的净优势平均.同样有趣的可能是[DragonEgg bench](http://www.phoronix.com/scan.php?page=article&item=llvm_dragonegg_30&num=3),DragonEgg是一个允许使用gcc前端(可能还有优化器)的插件然后是LLVM后端生成代码. (4认同)
  • 嗯...上次我检查时,我读了一篇发表各种基准测试的文章,其中clang几乎把gcc从水中吹走了.资料来源:http://clang.llvm.org/features.html#performance (2认同)

Man*_*rse 34

截至目前,GCC对C++ 11功能的支持比Clang更好,更完整.此外,GCC的代码生成器执行比Clang更好的优化(根据我的经验,我没有看到任何详尽的测试).

另一方面,Clang经常比GCC更快地编译代码,并在代码出现问题时产生更好的错误消息.

选择哪一个真正取决于对您来说重要的事情.我重视C++ 11支持和代码生成质量,而不是重视编译的便利性.因此,我使用GCC.对你而言,权衡可能会有所不同.

  • @segfault:这就是我目前正在做的事情.这个答案很古老,已经不再完全正确了.自从我写这篇文章以来,Clang和GCC都得到了显着的提升(特别是,Clang现在与GCC整体C++ 11支持相匹配,而GCC已经改进了它的错误消息和编译速度).现在我建议使用两者,稍微倾向于Clang,因为Clang源代码比GCC源更容易理解. (5认同)
  • 这是最新的Phoronix文章比较[GCC 4.6 vs Clang 3.0](http://www.phoronix.com/scan.php?page=article&item=llvm3_gcc_open64&num=1)以及[上一篇文章](http:// www.phoronix.com/scan.php?page=article&item=amd_bulldozer_compilers&num=1)特定于推土机平台.根据基准测试,获胜者是其中一个(在上一篇文章中,gcc 4.7也出现了),所以我个人觉得不清楚哪个表现更好. (3认同)

Ray*_*ger 23

我使用它们,因为有时它们会提供不同的,有用的错误消息

当其中一个核心开发人员首次尝试使用clang进行编译时,Python项目能够找到并修复许多小bug.

  • 使用Clang进行开发并使用GCC进行发布是合理的,但请确保您的GCC版本通过您的测试套件(使用和不使用NDEBUG). (5认同)
  • 谢谢你的回复.我已经尝试了一下,它的效果非常好.我也得到了不同的警告,这很棒. (2认同)

ide*_*n42 11

我同时使用了Clang和GCC,我发现Clang有一些有用的警告,但是对于我自己的光线跟踪基准 - 它一直比GCC慢5-15%(当然是用盐,但试图使用类似的优化标志对彼此而言).

所以现在我使用Clang静态分析及其对复杂宏的警告:(尽管现在GCC的警告非常好 - gcc4.8 - 4.9).

一些考虑:

  • Clang没有OpenMP支持,只有你利用它才有意义但是因为我这样做,这对我来说是一个限制.(*****)
  • 交叉编译可能不太受支持(例如FreeBSD 10仍然使用GCC4.x for ARM),例如gcc-mingw在Linux上可用...(YMMV).
  • 有些IDE还不支持解析Clangs输出(例如QtCreator*****).编辑:QtCreator现在支持Clang的输出
  • GCC的某些方面有更好的文档记录,并且由于GCC已存在更长时间且被广泛使用,您可能会发现更容易获得有关警告/错误消息的帮助.

***** - 这些领域正在积极开发中,可能很快就会得到支持


Fre*_*Foo 7

对于学生级别的课程,Clang的优势在于,默认情况下更严格.C标准.例如,GCC会在没有警告的情况下接受以下K&R版本的Hello World,但Clang拒绝了一些非常具有描述性的错误消息:

main()
{
    puts("Hello, world!");
}
Run Code Online (Sandbox Code Playgroud)

有了GCC,你必须-Werror让它真正指出这不是一个有效的C89程序.此外,您仍然需要使用c99gcc -std=c99获取C99语言.

  • 通常应该至少使用`-Wall`调用`gcc`,它会对此程序发出警告.但是,"clang"确实会产生良好的警告/错误. (7认同)
  • @caf:这正是我想要的点,GCC你必须传递它.开箱即用,它可能对教学目的过于宽容. (2认同)
  • @dreamlax:是的; 还有`gnu99`和`gnu ++ 98`和`gnu ++ 0x`.我认为那些是真正的*扩展*,即他们将编译符合ISO标准的代码顺便说一句.以下是详细信息:[for C](http://www.dis.com/gnu/gcc/C-Extensions.html),[for C++](http://www.dis.com/gnu/gcc/ C_002b_002b-Extensions.html). (2认同)