关键字"/>
C/C++语言中的restrict关键字
在C语言中,restrict关键字用于修饰指针(C99标准)。通过加上restrict关键字,编程者可提示编译器:在该指针的生命周期内,其指向的对象不会被别的指针所引用。
使用此关键字,将允许编译器预知多个指针之间的相互独立性,从而允许编译器做更加激进的优化。例如[1]:
int add(int *a, int *b){*a = 10;*b = 12;return *a + *b;
}
在这个函数中,有的同学就说了,直接返回22不就好了,这么想的同学就忽略了a==b的可能,如果a和b指向同一个地址,那么这个函数将返回24。实际上,编译器就是这个想要把额外操作去掉的“同学”,如果我们能清晰的告诉他,a和b在本函数中不管怎么移动都永远不可能指向相同的地址,那么,处理这个函数时,*a + *b 可以直接使用两立即数相加,不需要再从地址中读取值,就能优化代码执行的效率。
因此,在没有指明a不可能等于b的情况下,编译器能做到的最大优化就是,b指向地址的值一定是12,但a的值必须从地址中读取。
-O3
0000000000400a10 <_Z4add1PiS_>:400a10: c7 07 0a 00 00 00 movl $0xa,(%rdi) ; *a = 10400a16: c7 06 0c 00 00 00 movl $0xc,(%rsi) ; *b = 10400a1c: 8b 07 mov (%rdi),%eax ; 结果 = *a400a1e: 83 c0 0c add $0xc,%eax ; 结果 += 12 400a21: c3 retq
上面400a1c地址指令,读a。
于是我们可以使用restrict关键字告诉编译器,你放心优化,传入的指针a和指针b一定不指向同一个地址。
int add(int __restrict *a, int __restrict *b){*a = 10;*b = 12;return *a + *b;
}
那么编译器就顿悟了,知道a中的内容一定是10,b中的内容一定是12,a也不需要读。
0000000000400a30 <_Z4add2PiS_>:400a30: c7 07 0a 00 00 00 movl $0xa,(%rdi) ; *a = 10400a36: b8 16 00 00 00 mov $0x16,%eax ; 结果 = 22400a3b: c7 06 0c 00 00 00 movl $0xc,(%rsi) ; *b = 12400a41: c3 retq
于是编译后的代码直接采用立即数寻址的方式完成这个函数。整体上又比上一次优化中,少了一条指令。别看仅仅少了一条指令,在性能上,我们将两者分别执行1亿次,后者仅耗费了56ns,而前者耗费了146ns [1],性能上接近为后者的1/3。
[1]
更多推荐
C/C++语言中的restrict关键字
发布评论