将结构作为其第一个成员的别名是否是严格的别名违规?

M.M*_*M.M 23 c++ strict-aliasing language-lawyer reinterpret-cast

示例代码:

struct S { int x; };

int func()
{
     S s{2};
     return (int &)s;    // Equivalent to *reinterpret_cast<int *>(&s)
}
Run Code Online (Sandbox Code Playgroud)

我认为这很常见,被认为是可以接受的.该标准确保结构中没有初始填充.但是,这种情况未在严格别名规则(C++ 17 [basic.lval]/11)中列出:

如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:

  • (11.1)对象的动态类型,
  • (11.2)对象的动态类型的cv限定版本,
  • (11.3)与对象的动态类型类似(如7.5中所定义)的类型,
  • (11.4)与对象的动态类型对应的有符号或无符号类型的类型,
  • (11.5)一种类型,它是有符号或无符号类型,对应于对象动态类型的cv限定版本,
  • (11.6)聚合或联合类型,包括其元素或非静态数据成员中的上述类型之一(递归地,包括子聚合或包含联合的元素或非静态数据成员),
  • (11.7)一种类型,它是对象的动态类型的(可能是cv限定的)基类类型,
  • (11.8)char,unsigned char或std :: byte类型.

很明显,对象s正在访问其存储值.

项目符号点中列出的类型是执行访问的glvalue的类型,而不是被访问对象的类型.在这段代码中,glvalue类型int不是聚合类型或联合类型,排除了11.6.

我的问题是:这个代码是否正确,如果是,那么允许上述哪一个要点?

M.M*_*M.M 16

演员的行为归结为[expr.static.cast]/13;

"到指针类型的prvalue CV1 void "可以被转换成类型的prvalue"指针CV2 T ",其中T是一个对象类型和CV2是相同的CV-资格,或更大的CV-资格比,CV1.如果原始指针值表示A内存中字节的地址并且A不满足对齐要求T,则未指定结果指针值.否则,如果原始指针值指向一个对象a,并且存在一个b类型T(忽略cv-qualification)的对象,该对象是指针可互换a,则结果是指向的对象b.否则,转换指针值不变.

指针可互换的定义是:

如果出现以下情况,则两个对象a和b是指针可互换的:

  • 它们是同一个对象,或者
  • 一个是union对象,另一个是该对象的非静态数据成员,或
  • 一个是标准布局类对象,另一个是该对象的第一个非静态数据成员,或者,如果该对象没有非静态数据成员,则该对象的第一个基类子对象,或者
  • 存在对象c,使得a和c是指针可互换的,并且c和b是指针可互换的.

所以在原始代码中,s并且s.x指针可互换的,并且它遵循(int &)s实际指定s.x.

所以,在严格别名规则,其存储的值被访问的对象s.x,而不是s等有没有问题,代码是正确的.

  • 不相关指针类型之间的@Barry`reinterpret_cast`被定义为两个`static_cast`s的序列,通过`void*` (3认同)

Jos*_* D. 5

我认为它在expr.reinterpret.cast#11中

如果可以使用reinterpret_cast 将"指向T1的指针"类型的表达式显式转换为"指向T2的指针"x类型,则可以将指定对象的类型T1的glvalue表达式强制转换为"对T2的引用".结果是即 其中是一个指向型的"指针T1".没有创建临时,没有复制,也没有调用构造函数或转换函数[1].*reinterpret_­cast<T2 *>(p)px

[1] 当结果引用与源glvalue相同的对象时,这有时被称为类型双关语

支持@ MM关于指针不可挽回的答案:

来自cppreference:

假设对齐要求均得到满足,reinterpret_cast没有改变的外部指针的值数有限的情况下,处理指针相互转换的对象:

struct S { int a; } s;


int* p = reinterpret_cast<int*>(&s); // value of p is "pointer to s.a" because s.a
                                     // and s are pointer-interconvertible
*p = 2; // s.a is also 2
Run Code Online (Sandbox Code Playgroud)

struct S { int a; };

S s{2};
int i = (int &)s;    // Equivalent to *reinterpret_cast<int *>(&s)
                     // i doesn't change S.a;
Run Code Online (Sandbox Code Playgroud)