clang和gcc之间的区别

我在不同的项目中使用了这两个编译器。

它们在代码处理和输出生成方面有何不同? 例如, gccclang都有-O2选项用于优化。 它们在优化代码方面是否以相同的方式运行(高级别)? 我做了一点测试,例如,如果我有以下代码:

 int foo(int num) { if(num % 2 == 1) return num * num; else return num * num +1; } 

以下是带有-ng的clang和gcc的输出程序集:

 ----gcc 5.3.0----- ----clang 3.8.0---- foo(int): foo(int): movl %edi, %edx movl %edi, %eax shrl $31, %edx shrl $31, %eax leal (%rdi,%rdx), %eax addl %edi, %eax andl $1, %eax andl $-2, %eax subl %edx, %eax movl %edi, %ecx cmpl $1, %eax subl %eax, %ecx je .L5 imull %edi, %edi imull %edi, %edi cmpl $1, %ecx leal 1(%rdi), %eax setne %al ret movzbl %al, %eax .L5: addl %edi, %eax movl %edi, %eax retq imull %edi, %eax ret 

可以看出输出有不同的指令。 所以我的问题是其中一个在不同的项目中是否优于另一个?

是。 和不。

这就像询问奥迪汽车是否比梅赛德斯汽车更具优势。 和他们一样,这两个编译器是两个不同的项目,旨在做同样的事情。 在某些情况下, gcc会发出更好的代码,而在其他情况下则会发出clang

当您需要知道时,您必须用两者编译代码然后进行测量。

这里有一个论点, 在这里有点不太相关。

在这种情况下,Clang输出更好,因为它不分支; 相反,它将num % 2 == 1的值加载到由gcc使用跳转生成的代码中。 如果预期num为偶数/奇数且具有50%的几率,并且没有重复模式,则GCC生成的代码将易受分支预测失败的影响 。


但是,你可以通过这样做在GCC上使代码表现良好

 int foo(int num) { return num * num + (num % 2 != 1); } 

更重要的是,因为看起来你的算法实际上只是为无符号数定义,你应该使用unsigned int (它们对于负数是不同的) – 实际上你通过使用unsigned int作为参数来获得一个主要的加速,就像现在的GCC一样/ Clang可以将num % 2优化为num & 1

 unsigned int foo(unsigned int num) { return num * num + (num % 2 != 1); } 

生成的代码由gcc -O2生成

 movl %edi, %edx imull %edi, %edi andl $1, %edx xorl $1, %edx leal (%rdi,%rdx), %eax ret 

比任何一个编译器生成的原始函数的代码要好得多。 因此,编译器与知道他正在做什么的程序员一样重要。