我正在上大学,并且对于一个正在使用C的项目,我们已经探索了GCC和Clang,并且Clang似乎比GCC更友好。结果,我想知道使用clang(相对于GCC)在Linux上用C和C ++进行开发有什么优点或缺点?
就我而言,这将用于学生级别的课程,而不是生产课程。
如果使用Clang,应该使用GDB进行调试并使用GNU Make,还是使用其他调试器和make实用程序?
<atomic>
不支持C ++ 11 ,也许缺少其他一些小东西……我无法使用它,因此我并不完全了解它)。
我正在上大学,并且对于一个正在使用C的项目,我们已经探索了GCC和Clang,并且Clang似乎比GCC更友好。结果,我想知道使用clang(相对于GCC)在Linux上用C和C ++进行开发有什么优点或缺点?
就我而言,这将用于学生级别的课程,而不是生产课程。
如果使用Clang,应该使用GDB进行调试并使用GNU Make,还是使用其他调试器和make实用程序?
<atomic>
不支持C ++ 11 ,也许缺少其他一些小东西……我无法使用它,因此我并不完全了解它)。
Answers:
编辑:
海湾合作委员会的人员确实改善了海湾合作委员会(啊竞争)的诊断经验。他们创建了一个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
类之后,分号就消失了,对:)吗?
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对C ++ 11功能具有更好,更完整的支持。另外,GCC的代码生成器比Clang中的代码生成器执行更好的优化(以我的经验,我还没有看到任何详尽的测试)。
另一方面,Clang通常比GCC更快地编译代码,并且当您的代码有问题时会产生更好的错误消息。
使用哪种选择实际上取决于对您而言重要的事情。我重视C ++ 11支持和代码生成质量,而不是重视编译的便利性。因此,我使用GCC。对您而言,权衡可能会有所不同。
我使用这两种方法是因为有时它们会给出不同的,有用的错误消息。
当一位核心开发人员首次尝试使用clang进行编译时,Python项目能够找到并修复许多小buglet。
我同时使用Clang和GCC,但我发现Clang发出了一些有用的警告,但对于我自己的光线跟踪基准来说,它的速度始终比GCC慢5-15%(当然,要花点时间,但尝试使用类似的优化标记对彼此而言)。
因此,现在我将Clang静态分析及其警告与复杂的宏结合使用:(尽管现在,GCC的警告与gcc4.8-4.9一样好。)
一些注意事项:
*****- 这些领域正在积极开发中,并可能很快得到支持
对于学生级别的程序,Clang的好处是默认情况下会更严格。C标准。例如,下面的K&R版本的Hello World被GCC毫无警告地接受,但被Clang拒绝,并带有一些描述性的错误消息:
main()
{
puts("Hello, world!");
}
使用GCC,您必须给予它-Werror
才能真正指出这不是有效的C89程序。另外,您仍然需要使用c99
或gcc -std=c99
获取C99语言。
gcc
通常应使用至少调用-Wall
,它会对此程序发出警告。 clang
确实会产生良好的警告/错误。
我认为c可以替代。
GCC和clang在诸如的表达式上有一些区别a+++++a
,我与在Mac中使用clang而我使用gcc的同伴有很多不同的答案。
GCC已成为标准,clang可以替代。因为GCC非常稳定,而clang仍在开发中。
a+++++a
应该失败,因为它被解析为a ++ ++ + a
语法错误。