【发布时间】:2011-10-14 03:31:36
【问题描述】:
受this question 的启发,关于 SQLite3 中的以下代码:
static int strlen30(const char *z){
const char *z2 = z;
while( *z2 ){ z2++; }
return 0x3fffffff & (int)(z2 - z);
}
伴随着commit message 说明此功能有助于int 溢出。
我对这部分特别感兴趣:
const char *z2 = z;
while( *z2 ){ z2++; }
对我来说,这个循环推进z2 直到z2 指向空终止符。然后z2-z 产生字符串长度。
为什么不在这部分使用strlen() 并像这样重写:
return 0x3fffffff & (int)(strlen(z));
为什么使用循环+减法而不是strlen()?循环+减法可以做什么strlen()不能?
【问题讨论】:
-
我看到了另一个问题。看起来像是 NIH 综合症 (en.wikipedia.org/wiki/Not_Invented_Here),但我希望有更好的理由。
-
我真的不明白为什么这是近距离投票。我不问
strlen30()的意图是什么——这个函数做了一些额外的事情,我只问为什么要重新实现strlen()。 -
@0A0D:对我来说,循环将在非终止字符串上失败,就像
strlen()一样困难。 -
这段代码本身仍然存在与溢出相关的问题。
ptrdiff_t可能大于int,在这种情况下,该值可能超出int的范围。从技术上讲不是“溢出”,因为该术语严格意味着在int算术期间超出int的范围并且是UB,但转换的结果是实现定义的,因此它不一定很有用。因此,要么代码仍然存在缺陷,要么在庞大的 sqlite 代码或文档中的某处对实现行为有一些额外的假设...... -
可能注释的意思不是这个函数永远不会溢出,而是调用者对结果所做的事情永远不会溢出。剪辑到 30 位具有您可以执行
strlen30(a) + strlen30(b)的属性,结果适合 32 位签名int而不会溢出。该结果可能完全没有意义,因为在strlen30中截断了一个值,但该添加(例如字符串连接)不会溢出。
标签: c++ c string sqlite strlen