【发布时间】:2013-12-17 05:15:42
【问题描述】:
(免责声明:我已经看过this question,我不会再问了——我对为什么代码有效,而不感兴趣em>如何工作。)
所以here's 这是 Apple(好吧,FreeBSD 的)strlen() 的实现。它使用了一个众所周知的优化技巧,即一次检查 4 或 8 个字节,而不是与 0 进行逐字节比较:
size_t strlen(const char *str)
{
const char *p;
const unsigned long *lp;
/* Skip the first few bytes until we have an aligned p */
for (p = str; (uintptr_t)p & LONGPTR_MASK; p++)
if (*p == '\0')
return (p - str);
/* Scan the rest of the string using word sized operation */
for (lp = (const unsigned long *)p; ; lp++)
if ((*lp - mask01) & mask80) {
p = (const char *)(lp);
testbyte(0);
testbyte(1);
testbyte(2);
testbyte(3);
#if (LONG_BIT >= 64)
testbyte(4);
testbyte(5);
testbyte(6);
testbyte(7);
#endif
}
/* NOTREACHED */
return (0);
}
现在我的问题是:也许我错过了明显的,但这不能读到字符串的末尾吗?如果我们有一个长度不能被字长整除的字符串怎么办?想象以下场景:
|<---------------- all your memories are belong to us --------------->|<-- not our memory -->
+-------------+-------------+-------------+-------------+-------------+ - -
| 'A' | 'B' | 'C' | 'D' | 0 |
+-------------+-------------+-------------+-------------+-------------+ - -
^ ^^
| ||
+------------------------------------------------------++-------------- - -
long word #1 long word #2
当读取第二个长字时,程序访问了它实际上不应该访问的字节......这不是错了吗?我非常有信心 Apple 和 BSD 人员知道他们在做什么,所以有人可以解释一下为什么这是正确的吗?
我注意到的一件事是beerboy asserted this to be undefined behavior,我也相信确实如此,但有人告诉他事实并非如此,因为“我们将单词大小与初始 for 循环对齐”(此处未显示)。但是,如果数组不够长并且我们正在读取它的末尾,我根本不明白为什么对齐会有任何相关性。
【问题讨论】:
-
注意:除了潜在的 UB 得到很好的回答之外,该方法的 "5.2 times as fast" 利用
char通常是 ASCII(代码 0 - 127)本身值得注意。 -
作为一般原则,出现在标准库实现中的代码在标准 C 环境中不存在。有时这是为了代码的“好处”——它可以依赖标准不提供的特定于实现的保证,就像在这种情况下一样。有时这是对代码的“损害”——例如,可能有一个明显的 X 以 Y 的实现,你不能这样做,因为你已经选择了 Y 的明显的 X 实现。
标签: c undefined-behavior