【发布时间】:2023-03-17 23:30:01
【问题描述】:
我已经阅读了一段时间的严格别名规则,但我开始感到非常困惑。首先,我已经阅读了这些问题和一些答案:
- strict-aliasing-rule-and-char-pointers
- when-is-char-safe-for-strict-pointer-aliasing
- is-the-strict-aliasing-rule-really-a-two-way-street
据他们说(据我所知),使用指向另一种类型的指针访问 char 缓冲区违反了严格的别名规则。但是,strlen() 的 glibc 实现有这样的代码(删除了 cmets 和 64 位实现):
size_t strlen(const char *str)
{
const char *char_ptr;
const unsigned long int *longword_ptr;
unsigned long int longword, magic_bits, himagic, lomagic;
for (char_ptr = str; ((unsigned long int) char_ptr
& (sizeof (longword) - 1)) != 0; ++char_ptr)
if (*char_ptr == '\0')
return char_ptr - str;
longword_ptr = (unsigned long int *) char_ptr;
himagic = 0x80808080L;
lomagic = 0x01010101L;
for (;;)
{
longword = *longword_ptr++;
if (((longword - lomagic) & himagic) != 0)
{
const char *cp = (const char *) (longword_ptr - 1);
if (cp[0] == 0)
return cp - str;
if (cp[1] == 0)
return cp - str + 1;
if (cp[2] == 0)
return cp - str + 2;
if (cp[3] == 0)
return cp - str + 3;
}
}
}
longword_ptr = (unsigned long int *) char_ptr; 行显然将unsigned long int 别名为char。我不明白是什么让这成为可能。我看到代码处理了对齐问题,所以没有问题,但我认为这与严格的别名规则无关。
第三个链接问题的接受答案是:
但是,有一个非常常见的编译器扩展允许您将正确对齐的指针从 char 转换为其他类型并访问它们,但这不是标准的。
我唯一想到的是-fno-strict-aliasing 选项,是这样吗?我在任何地方都找不到它记录了 glibc 实现者所依赖的任何地方,并且 cmets 以某种方式暗示这种转换是在没有任何问题的情况下完成的,很明显不会有任何问题。这让我觉得这确实很明显,我错过了一些愚蠢的东西,但我的搜索失败了。
【问题讨论】:
-
代码可能只是写得不好。转换指针
(unsigned long int) char_ptr的对齐检查也很可疑。他们经历了所有这些麻烦来尝试一些奇怪的优化,这些优化增加了额外的分支,而且看起来不一定更快,可能更慢。 -
那么,如果 GNU 人(AFAIK 和 FreeBSD 人也应用了类似的优化)如果没有加快速度,为什么还要经历这一切呢?
-
@curiousguy 很多人,我想。在过去的 5-10 年里,GCC 在各种嵌入式系统编程中变得非常流行。并且因此在此类系统上不断出现错误,其中大多数实际上是由 gcc 基于严格别名的积极优化引起的。
-
相关的 glibc 邮件列表帖子:sourceware.org/ml/libc-alpha/2016-02/msg00052.html
标签: c glibc strict-aliasing