我的 Linux 开发项目中的 Clang 与 GCC

我在上大学,对于一个项目,我们使用 C。我们已经探索了 GCC 和 Clang,Clang 似乎比 GCC 更加用户友好。因此,我想知道使用 clang (相对于 GCC)在 Linux 上的 C 和 C + + 中开发有哪些优点或缺点?

在我的情况下,这将用于学生水平的计划,而不是生产。

如果我使用 Clang,我应该使用 GDB 进行调试并使用 GNUMake,还是使用另一个调试器并使用 Make 实用程序?

115870 次浏览

对于学生水平的课程,Clang 的好处是,默认情况下,它是更严格的 C 标准。例如,以下 Hello World 的 K & R 版本在没有警告的情况下被 GCC 接受,但是被 Clang 拒绝,并且出现了一些描述性很强的错误消息:

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

对于 GCC,您必须给它 -Werror以使它真正表明这不是一个有效的 C89程序。此外,您仍然需要使用 c99gcc -std=c99来获得 C99语言。

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

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

到目前为止,GCC 对 C + + 11特性的支持比 Clang 更好,也更完整。此外,GCC 的代码生成器比 Clang 中的代码生成器执行更好的优化(根据我的经验,我没有看到任何详尽的测试)。

另一方面,Clang 通常比 GCC 更快地编译代码,并且在代码出错时产生更好的错误消息。

选择使用哪一个真正取决于什么东西对你来说是重要的。我更看重 C + + 11支持和代码生成质量,而不是编译的便利性。因此,我使用海湾合作委员会。对你来说,取舍可能是不同的。

编辑:

Gcc 的人真的改善了 gcc (啊竞赛)的诊断经验。他们创建了一个维基页面来展示 给你。Gcc 4.8现在也有很好的诊断功能(gcc 4.9 x 添加了彩色支持)。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类的定义之后,分号丢失了,对吗:) ?

好吧,海湾合作委员会也注意到了,勉强算是吧:

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 避免了大量错误。没必要把学生吓跑。

我同时使用 Clang 和 GCC,我发现 Clang 有一些有用的警告,但是对于我自己的光线跟踪基准测试来说——它始终比 GCC (当然对此持保留态度,但尝试对两者使用类似的优化标志)。慢5-15%

因此,现在我使用 Clang 静态分析及其警告来处理复杂的宏: (尽管现在 GCC 的警告几乎和 good-gcc4.8-4.9一样好)。

一些考虑:

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

- 你好-你好

我觉得叮当声可以作为替代。

GCC 和 clang 在像 a+++++a这样的表达式上有一些不同,我和我的同行得到了许多不同的答案,他们在 Mac 上使用 clang,而我使用 GCC。

海湾合作委员会已经成为标准,叮当声可以作为一种替代。因为海湾合作委员会是非常稳定和叮当仍在发展。