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


175

我正在上大学,并且对于一个正在使用C的项目,我们已经探索了GCC和Clang,并且Clang似乎比GCC更友好。结果,我想知道使用clang(相对于GCC)在Linux上用C和C ++进行开发有什么优点或缺点?

就我而言,这将用于学生级别的课程,而不是生产课程。

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


7
据我所知,Clang距离“成熟”还很遥远,尤其是在标准库支持方面。尽管如此,它仍然具有奇妙的错误消息,因此您始终可以通过在Clang上尝试代码来解决神秘的编译器错误。我相信Clang也可以将C ++编译为C。
Kerrek SB 2011年

3
@KerrekSB:lang缺少“标准库支持”的哪些元素?
斯蒂芬·佳能

2
@StephenCanon:上次尝试时,我不得不使用libstdc ++(据我所知,它不是Clang的一部分)。而就在前几天,我们遇到了这个问题。无论如何,我没有遵循最新趋势,所以我的观点可能完全过时了。
Kerrek SB 2011年

4
@KerrekSB:关于您的链接,Clang在纯Windows上不起作用。它可以在MinGW中运行。关于标准库,目前Clang没有真正的标准库部分。Clang与OSX上的libc ++捆绑在一起,但是libc ++在其他环境中并未完全移植,因此在那些Clang上需要安装另一个标准库实现。在Linux上,libstdc ++有效。
Matthieu M.

1
@KerrekSB:100%支持C ++ 98。大多数情况下都支持C ++ 11(上次我检查过,<atomic>不支持C ++ 11 ,也许缺少其他一些小东西……我无法使用它,因此我并不完全了解它)。
James McNellis

Answers:


122

编辑:

海湾合作委员会的人员确实改善了海湾合作委员会(啊竞争)的诊断经验。他们创建了一个Wiki页面在此处进行展示。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";
}

您会马上注意到,在定义了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>]

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.

我故意选择一个示例,该示例会触发一个不清楚的错误消息(源于语法上的歧义),而不是典型的“哦,我的上帝Clang读了我的思想”示例。尽管如此,我们注意到Clang避免了大量错误。无需将学生吓跑。


2
嗯...上次我查看了一篇发表了各种基准测试的文章,其中在测试中,c声几乎使gcc掉光了。来源:clang.llvm.org/features.html#performance

31
@AscensionSystems:当心,这些测试显示的是Clang二进制本身的性能(那是前一段时间),而不是您正在编译的二进制的性能。
Matthieu M.

我很想看到编译后的可执行文件之间的比较,这是一个好主意。我觉得clang在优化方面做得更好,但我实际上没有看到任何基准。我会检查一下。

4
@AscensionSystems:这是我所知道的最新板凳,它将gcc 4.6与llvm 3.0进行了比较,显示了gcc的平均优势。同样有趣的是DragonEgg bench,DragonEgg是一个插件,允许使用gcc前端(可能还有优化器),然后使用LLVM后端生成代码。
Matthieu M.

1
上次我检查时,phoronix基准测试非常不可信:编译器标记未正确记录,但结果表明未正确设置。
Eamon Nerbonne

35

截至目前,与Clang相比,GCC对C ++ 11功能具有更好,更完整的支持。另外,GCC的代码生成器比Clang中的代码生成器执行更好的优化(以我的经验,我还没有看到任何详尽的测试)。

另一方面,Clang通常比GCC更快地编译代码,并且当您的代码有问题时会产生更好的错误消息。

使用哪种选择实际上取决于对您而言重要的事情。我重视C ++ 11支持和代码生成质量,而不是重视编译的便利性。因此,我使用GCC。对您而言,权衡可能会有所不同。


3
这是最新的Phoronix文章,将GCC 4.6与Clang 3.0进行了比较,以及之前针对推土机平台的文章。根据基准测试,获胜者可能是一个,也可能是另一个(在上一篇文章中,gcc 4.7也会出现),因此我个人不清楚哪个性能更好。
Matthieu M.

为什么不同时使用两者?Clang用于开发,GCC用于生产。
segfault

5
@segfault:那就是我目前正在做的。这个答案已经很老了,不再完全正确。自从我编写Clang和GCC以来,它们的性能都有了显着提高(特别是Clang现在与GCC总体上支持C ++ 11匹配,并且GCC改进了其错误消息和编译速度)。现在,我建议您同时使用Clang和CCC,因为Clang源代码比GCC源代码更容易理解。
Mankarse 2013年

23

我使用这两种方法是因为有时它们会给出不同的,有用的错误消息。

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


1
您对使用clang进行调试构建而对gcc进行优化发行有何想法?
Olical 2012年

5
使用Clang进行开发并使用GCC发行是合理的,但是请确保您的GCC发行版通过了您的测试套件(带有和不带有NDEBUG的测试套件)。
Raymond Hettinger 2012年

2
感谢您的回复。我已经尝试了一下,效果确实很好。我也收到不同的警告,这很棒。
Olical 2012年

11

我同时使用Clang和GCC,但我发现Clang发出了一些有用的警告,但对于我自己的光线跟踪基准来说,它的速度始终比GCC慢5-15%(当然,要花点时间,但尝试使用类似的优化标记对彼此而言)。

因此,现在我将Clang静态分析及其警告与复杂的宏结合使用:(尽管现在,GCC的警告与gcc4.8-4.9一样好。)

一些注意事项:

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

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


我也使用OpenMP,但是我正在考虑切换到TBB,我想它可以与Clang一起使用。

1
在某些情况下,TBB可能是OpenMP的可行替代方案(但据我所知仅适用于C ++),因为C不支持C –对于大型项目,从OpenMP切换到其他项目可能不值得,尤其是如果Clang最终会无论如何都支持OpenMP。
ideaman42

7

对于学生级别的程序,Clang的好处是默认情况下会更严格。C标准。例如,下面的K&R版本的Hello World被GCC毫无警告地接受,但被Clang拒绝,并带有一些描述性的错误消息:

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

使用GCC,您必须给予它-Werror才能真正指出这不是有效的C89程序。另外,您仍然需要使用c99gcc -std=c99获取C99语言。


8
gcc通常应使用至少调用-Wall,它会对此程序发出警告。 clang确实会产生良好的警告/错误。
caf

2
@caf:这正是我要提出的要点,对于GCC,您必须传递它选项。开箱即用,对于教学目的可能太宽容了。
Fred Foo

可能是正确的,但这是相当次要的一点。更重要的是错误消息的质量。GCC 4.6相当不错,尽管我知道clang在这里做了一些真正的魔术。
Kerrek SB 2011年

2
@dreamlax:是的;还有gnu99gnu++98gnu++0x。我认为这些都是真正的扩展,即它们将毫无问题地编译符合ISO标准的代码。这是详细信息:对于C对于C ++
Kerrek SB 2011年

1
该程序不应产生错误或警告。符合标准。
Miles Rout

3

我认为c可以替代。

GCC和clang在诸如的表达式上有一些区别a+++++a,我与在Mac中使用clang而我使用gcc的同伴有很多不同的答案。

GCC已成为标准,clang可以替代。因为GCC非常稳定,而clang仍在开发中。


5
Clang正在迅速准备在Linux世界中完全取代GCC,并且在BSD世界中已经做了很大的努力。几年前,它取代了Mac上的GCC。lang是好东西。我个人认为GCC可以成为替代方案,对此我会感到高兴。
coder543

5
表达式a +++++ a是未定义的,因此期望在每个编译器上,甚至在同一编译器的不同版本上都得到不同的答案。在不同的时间编译时,您甚至可以在同一编译器上获得该表达式的不同结果。这就是“未定义”的意思。
Lelanthran

1
a+++++a应该失败,因为它被解析为a ++ ++ + a语法错误。
Miles Rout 2014年

@Lelanthran并不是未定义的意思。它具有未定义的行为,因此编译器可能无法编译该行为,或者它可能在运行时抛出或锁定CPU,因此您需要进行硬复位或其他更危险的操作。
安蒂·哈帕拉
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.