考虑下一个代码:

unsigned idx;
//.. some work with idx
if( idx >= idx_max )
    idx %= idx_max;

可以简化为仅第二行:

idx %= idx_max;

也会达到同样的效果.


有几次我遇到了下一个代码:

unsigned x;
//... some work with x
if( x!=0 )
  x=0;

可以简化为

x=0;

这些问题包括:

  • 使用if有意义吗?为什么?特别是具有ARM拇指指令集的情况下.
  • if张可以省略吗?
  • 编译了什么优化?

推荐答案

如果您想了解编译器在做什么,您只需要拉出一些程序集.我推荐这个网站(我已经输入了问题中的代码):https://godbolt.org/g/FwZZOb.

第一个示例更有趣.

int div(unsigned int num, unsigned int num2) {
    if( num >= num2 ) return num % num2;
    return num;
}

int div2(unsigned int num, unsigned int num2) {
    return num % num2;
}

生成:

div(unsigned int, unsigned int):          # @div(unsigned int, unsigned int)
        mov     eax, edi
        cmp     eax, esi
        jb      .LBB0_2
        xor     edx, edx
        div     esi
        mov     eax, edx
.LBB0_2:
        ret

div2(unsigned int, unsigned int):         # @div2(unsigned int, unsigned int)
        xor     edx, edx
        mov     eax, edi
        div     esi
        mov     eax, edx
        ret

基本上,出于非常具体和合乎逻辑的原因,编译器将not优化掉分支.如果整数除法与比较的成本大致相同,那么分支将非常没有意义.但是整数除法(通常和整数除法一起进行)实际上非常昂贵:http://www.agner.org/optimize/instruction_tables.pdf.这些数字因体系 struct 和整数大小的不同而有很大差异,但通常的延迟可能在15到接近http://www.agner.org/optimize/instruction_tables.pdf个周期之间.

通过在执行模数之前获取一个分支,实际上可以节省大量工作.不过请注意:编译器也不会将没有分支的代码转换为程序集级别的分支.这是因为分支也有一个缺点:如果模数最终仍然是必需的,那么你只是浪费了一点时间.

在不知道idx < idx_max为真的相对频率的情况下,无法对正确的优化做出合理的确定.因此,编译器(GCC和Clang做同样的事情) Select 以相对透明的方式映射代码,将此 Select 权留给开发人员.

因此,分支机构可能是一个非常合理的 Select .

第二个分支应该是完全没有意义的,因为比较和赋值are的可比成本.也就是说,您可以在链接中看到,如果编译器引用了该变量,则它们仍然不会执行此优化.如果值是局部变量(如您演示的代码中所示),则编译器将优化分支.

总之,第一段代码可能是一个合理的优化,第二段代码可能只是一个疲惫的程序员.

C++相关问答推荐

如何将一个integer与一个数组进行比较?

数组元素的编号索引

Mbed TLS:OAEP的就地en—/decryption似乎不起作用'

无效使用未定义类型'structsquare'?

需要大整数和浮点数.使用long long int和long double

如何使用低级C++写出数值

ARM64 ASIMD固有的加载uint8_t* 到uint16x8(x3)?

如何在C中通过套接字自定义数据类型读取原始变量?

使用双指针动态分配和初始化2D数组

具有交换链获取和命令缓冲区提交的同步-危险-读后写错误

`#if`条件中是否允许`sizeof`?

使用TCL C API导航到列表中的元素

链接到底是如何工作的,我在这里到底做错了什么

搜索使用int代替time_t的用法

如何在c中使用具有不同变量类型的内存分配?

STM32 FATFS用户手册(Um1721)中的代码正确吗?

在我的第一个C语言中观察到的错误';你好世界';程序

关于不同C编译器中的__attribute__支持

macos/arm64 上地址空间不使用第一位吗?

如何转义包含指令中的字符?