表达式中的严格别名

假设我们有以下代码:

#include <stdio.h>
#include <stdint.h>

int main()
{
    uint16_t a[] = { 1, 2, 3, 4 };
    const size_t n = sizeof(a) / sizeof(uint16_t);
    
    for (size_t i = 0; i < n; i++) {
        uint16_t *b = (uint16_t *) ((uint8_t *) a + i * sizeof(uint16_t));
        printf("%un", *b);
    }
    
    return 0;
}

显然,转换auint8_t指针并不违反,所以这个问题是关于将结果指针转换为uint16_t指针。根据我的理解,根据标准,它确实违反了严格的别名规则。但是,我不知道从实际情况来看,由于种类ab兼容。唯一可能的违规是将仅存在于这个表达式中buint8_t指针别名化。所以在我的理解中,即使它违反了规则,我也会怀疑它会导致未定义的行为。它可以?

请注意,我并不是说这段代码是有意义的。这个问题纯粹是出于对严格别名的理解的教育目的。

回答

不是严格的别名违规。

由于向指针到字符类型的转换给出了例外,atouint8_t和后续指针算术的转换是安全的。

C 标准的第 6.3.2.3p7 节规定:

指向对象类型的指针可以转换为指向不同对象类型的指针。如果结果指针未正确对齐 68) 引用类型,则行为未定义。否则,当再次转换回来时,结果将与理论指针相等。 当指向对象的指针转换为指向字符类型的指针时,结果指向对象的最低地址字节。结果的连续增量,直到对象的大小,产生指向对象剩余字节的指针。

转换回和随后的取消引用是安全的,因为b它指向一个类型的对象uint16_t(特别是数组的成员a),匹配 的指向类型b

第 6.5p7 节指出:

对象的存储值只能由具有以下类型之一的左值表达式访问:

  • 与对象的有效类型兼容的类型,
  • 与对象的有效类型兼容的类型的限定版本,
  • 一种类型,它是与对象的有效类型相对应的有符号或无符号类型,
  • 一种类型,它是与对象有效类型的限定版本相对应的有符号或无符号类型,
  • 在其成员中包含上述类型之一的聚合或联合类型(递归地包括子聚合或包含联合的成员),或
  • 一种字符类型。
  • @KamilCuk That's not strictly safe because you don't have an array of type `uint16_t` that you are allowed to do arithmetic on. 6.3.2.3p7 specifically allows for pointer arithmetic on a character type to access the object's representation.

以上是表达式中的严格别名的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>