【发布时间】:2011-01-04 04:52:36
【问题描述】:
下面的 strlen() 函数是否只被调用一次(存储的值以供进一步比较);还是每次进行比较时都会调用它?
for (i = 0; i < strlen(word); i++)
{ /* do stuff */ }
【问题讨论】:
下面的 strlen() 函数是否只被调用一次(存储的值以供进一步比较);还是每次进行比较时都会调用它?
for (i = 0; i < strlen(word); i++)
{ /* do stuff */ }
【问题讨论】:
这取决于实现。通常,它每次都会被调用,但是,如果编译器可以看到 word 永远不会改变,并且 strlen 是一个纯函数(没有副作用),它可以取消调用。
请参阅:http://underhanded.xcott.com/?page_id=15,了解一个众所周知的被利用示例。 :-)
【讨论】:
word 传递给采用char const * 的函数。如果word 是非限制性的,那么在某处可能有一个全局char*,被调用者修改,而这恰好是word 的别名。如果被调用者在不同的翻译单元中,并且没有以某种方式标记为纯,编译器几乎肯定不能排除这种情况,尽管整个程序优化可能会再试一次。基本上,如果循环体没有完全内联,那么不要屏住呼吸。
restrict 参数仅相对于其他参数没有别名,并不是说所述参数不存在别名——在这种情况下,就像你说的那样,你仍然被塞满了——如果全局指针被保存在某处,程序分析。
word 声明为const 实际上并不意味着它不能在循环内更改。
我有时会将其编码为 ...
for (int i = 0, n = strlen(word); i < n; ++i) { /* do stuff */ }
... 这样 strlen 只被调用一次(以提高性能)。
【讨论】:
将针对循环的每次迭代进行评估(编辑:如有必要)。
就像 Tatu 说的,如果 word 的长度不会改变,你可以在 for 循环之前调用 strlen。但正如 Chris 所说,编译器可能足以意识到 word 无法更改,并自行消除重复调用。
但是如果word 可以在循环期间改变长度,那么当然您需要将strlen 调用保持在循环条件中。
【讨论】:
word 没有在循环体中更改或声明为volatile,大多数编译器都应该对此进行优化;与往常一样,您可以检查(反)汇编,看看会发生什么......
word 相同的内存。如果 word 在 C99 中用关键字 restrict 标记,那么它可以做出这样的假设,并且在极少数情况下它可能能够证明没有别名。但是如果没有看到循环体,就不能说这是一个简单的优化。
strlen(word) 的执行次数取决于:
word被声明为常量(数据是常量)word 没有改变。举个例子:
char word[256] = "Grow";
for (i = 0; i < strlen(word); ++i)
{
strcat(word, "*");
}
在此示例中,变量 word 使用循环进行修改:
0) “成长” -- 长度 == 4
1) "增长*" -- 长度 == 5
2) “成长**”——长度 == 6
但是,编译器可以分解出strlen 调用,因此如果变量word 被声明为常量,则它会被调用一次:
void my_function(const char * word)
{
for (i = 0; i < strlen(word); ++i)
{
printf("%d) %s\n", i, word);
}
return;
}
函数已声明变量word 是常量数据(实际上,一个指向常量数据的指针)。因此长度不会改变,因此编译器只能调用一次strlen。
如有疑问,您始终可以自己执行优化,在这种情况下,这可能会提供更易读的代码。
【讨论】:
const-qualified 指针只是保证指针不会通过该特定变量(不进行强制转换)更改,而不是数据本身是不可变的。
char * 指向的数据没有改变!或者如果任何内存被修改,因为 char 指针可能指向那个...
【讨论】:
strlen 可以被无限次调用(假设编译器没有缓存strlen() 的结果)。跨度>
i 也不会被修改。
每次迭代都会调用它。下面的代码只调用一次strlen函数。
for (i = 0, j = strlen(word); i < j i++)
{ /* do stuff */ }
【讨论】: