表达式中的严格别名
Strict aliasing within an expression
假设我们有以下代码:
#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("%u\n", *b);
}
return 0;
}
很明显,将 a
转换为 uint8_t
指针并不违规,所以这个问题是关于将结果指针转换为 uint16_t
指针。据我了解,根据标准,它确实违反了严格的别名规则。但是,从实用的角度我不确定,因为 a
和 b
的类型是兼容的。唯一可能的违规行为是 b
别名 uint8_t
指针,它只存在于这个表达式中。所以在我的理解中,即使它违反了规则,我也会怀疑它会导致未定义的行为。可以吗?
请注意,我并不是说这段代码有意义。这个问题是为了纯粹的教育目的,关于理解严格的别名。
这不是严格的别名违规。
a
到 uint8_t
的转换以及后续的指针算法是安全的,因为转换为指向字符的指针类型存在异常。
C standard 的第 6.3.2.3p7 节指出:
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned68)for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to theo riginal pointer. When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.
转换回和随后的取消引用是安全的,因为 b
指向类型 uint16_t
的对象(特别是数组 a
的成员),匹配指向的对象b
.
的类型
第 6.5p7 节指出:
An object shall have its stored value accessed only by an lvalue
expression that has one of the following types:
- a type compatible with the effective type of the object,
- a qualified version of a type compatible with the effective type of the object,
- a type that is the signed or unsigned type corresponding to the effective type of the object,
- a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
- an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a
member of a subaggregate or contained union), or
- a character type.
假设我们有以下代码:
#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("%u\n", *b);
}
return 0;
}
很明显,将 a
转换为 uint8_t
指针并不违规,所以这个问题是关于将结果指针转换为 uint16_t
指针。据我了解,根据标准,它确实违反了严格的别名规则。但是,从实用的角度我不确定,因为 a
和 b
的类型是兼容的。唯一可能的违规行为是 b
别名 uint8_t
指针,它只存在于这个表达式中。所以在我的理解中,即使它违反了规则,我也会怀疑它会导致未定义的行为。可以吗?
请注意,我并不是说这段代码有意义。这个问题是为了纯粹的教育目的,关于理解严格的别名。
这不是严格的别名违规。
a
到 uint8_t
的转换以及后续的指针算法是安全的,因为转换为指向字符的指针类型存在异常。
C standard 的第 6.3.2.3p7 节指出:
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned68)for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to theo riginal pointer. When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.
转换回和随后的取消引用是安全的,因为 b
指向类型 uint16_t
的对象(特别是数组 a
的成员),匹配指向的对象b
.
第 6.5p7 节指出:
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
- a type compatible with the effective type of the object,
- a qualified version of a type compatible with the effective type of the object,
- a type that is the signed or unsigned type corresponding to the effective type of the object,
- a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
- an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
- a character type.