Maybe,具体取决于编译器.让我们来看一些例子,它们是用GCC 13.2.0和clang 17.0.1编译的,都是在优化级别-O3
和with extensions enabled(注意,strnlen
是POSIX,而不是标准C).
int p() {
char mystring[32] = "this is a long line";
return strnlen(mystring, 32) > 2;
}
Cang和GCC都将其优化为mov eax, 1; ret
.这是因为它们知道strnlen
的行为,并且可以替换调用的返回值,而不需要在运行时计算它.(在GCC,这个数字是implemented via __builtin_strnlen
).
如果strnlen
函数不是已知的内置函数,但可以内联:
inline int my_strnlen(char const* s, int n) {
for (int i = 0; i != n; ++i)
if (s[i] == 0)
return i;
return n;
}
int p() {
char mystring[32] = "this is a long line";
return my_strnlen(mystring, 32) > 2;
}
在这里,叮当优化到mov eax, 1
,但GCC发出一个循环.
最后,对于标记为pure
的未知谓词,告诉优化器它没有副作用:
__attribute__((pure)) int f(char);
inline int my_strnlen_f(char const* s, int n) {
for (int i = 0; i != n; ++i)
if (f(s[i]))
return i;
return n;
}
int p() {
char mystring[32] = "this is a long line";
return my_strnlen_f(mystring, 32) > 2;
}
GCC再次发出一个循环;clang发出一些相当笨拙的代码,但这表明它知道调用f
不超过3次:
p: # @p
push rbx
mov edi, 116
call f@PLT
xor ebx, ebx
test eax, eax
je .LBB2_1
.LBB2_3:
mov eax, ebx
pop rbx
ret
.LBB2_1:
mov edi, 104
call f@PLT
test eax, eax
jne .LBB2_3
mov edi, 105
call f@PLT
xor ebx, ebx
test eax, eax
sete bl
mov eax, ebx
pop rbx
ret
不,在这种情况下,C语言只会将缓冲区大小设置为
字符串文字(终止符的字符串长度+1).
- 如果我从if内部表达式中删除了圆括号,会有什么关系吗?
不,优化器在不包括这些语法细节的程序表示上运行.
几乎可以肯定的是,优化器能够理解它们是等价的.