翻译《有关编程、重构及其他的终极问题?》——18.你在一个语言上积累的经验和知识不总是适用于另外一门语言
标签(空格分隔): 翻译 技术 C/C++
作者:Andrey Karpov
翻译者:顾笑群 - Rafael Gu
最后更新:2017年02月21日
18.你在一个语言上积累的经验和知识不总是适用于另外一门语言
下面这段代码来自Putty项目。PVS-Studio诊断的低效代码说明为:V814 Decreased performance. Calls to the ‘strlen’ function have being made multiple times when a condition for the loop’s continuation was calculated(译者注:大意是代码的效率不高,应为strlen在循环判断条件中重复调用了)。
static void tell_str(FILE * stream, char *str)
{
unsigned int i;
for (i = 0; i < strlen(str); ++i)
tell_char(stream, str[i]);
}
解释
实际上这里并没有错误,但因为在每个循环中strlen()函数都被调用了,所以在处理长字符串时这段代码会及其低效。如果一定要说错误,低效的代码算是吧。
比较常见的是,类似这类典型的代码一般都是由原来熟悉Pascal(或Delphi)语言的程序员写的。在Pascal语言中,在循环中的退出判断语句只被计算一次,所以前面的代码(对于Pascal)是合适而且非常常用的。
让我们看一下用Pascal语言的例子。“called”这个单词将被仅仅被打印一次,因为pstrlen()只被调用了一次。
program test;
var
i : integer;
str : string;
function pstrlen(str : string): integer;
begin
writeln('called');
pstrlen := Length(str);
end;
begin
str := 'a pascal string';
for i:= 1 to pstrlen(str) do
writeln(str[i]);
end.
高效的代码
static void tell_str(FILE * stream, char *str)
{
size_t i;
const size_t len = strlen(str);
for (i = 0; i < len; ++i)
tell_char(stream, str[i]);
}
建议
不用忘记在C/C++中,循环中的条件判断条件每次循环都会被重新计算。因此使用一个低效缓慢的函数作为判断表达式的一部分不是一个好主意,特别是在进入循环前可以只计算一次的情况下(译者注:前面的例子就是)。
在一些情况下,编译器也许可以优化类似strlen()被计算多次的情况。比如指针始终指向同一个字符串的情况,但我们不能依赖于此。