我在上大学,在一个我们使用 C 的项目中。我们探索了 GCC 和 Clang,而 Clang 似乎比 GCC 对用户更友好。因此,我想知道在 Linux 上使用 C 和 C++ 进行开发时,使用 clang 而不是 GCC 有什么优点或缺点?
就我而言,这将用于学生级别的课程,而不是生产。
如果我使用 Clang,我应该使用 GDB 调试并使用 GNU Make,还是使用另一个调试器和 make 实用程序?
编辑:
gcc 的家伙确实提高了 gcc 的诊断体验(啊比赛)。他们创建了一个 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,对吧 :) ?
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 避免了错误的泛滥。没有必要吓跑学生。