首页 文章

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

提问于
浏览
21

示例代码:

struct S { int x; };

int func()
{
     S s{2};
     return (int &)s;    // Equivalent to *reinterpret_cast<int *>(&s)
}

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

如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:(11.1)对象的动态类型,(11.2)动态的cv限定版本对象的类型,(11.3)与对象的动态类型相似的类型(如7.5中所定义),(11.4)对应于对象的动态类型的有符号或无符号类型,(11.5)a type是有符号或无符号类型,对应于对象动态类型的cv限定版本,(11.6)聚合或联合类型,包括其元素或非静态数据成员中的上述类型之一(包括,递归地,子聚合或包含联合的元素或非静态数据成员,(11.7)一种类型,它是对象动态类型的(可能是cv限定的)基类类型,(11.8)一个char,unsigned char或std :: byte类型 .

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

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

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

2 回答

  • 16

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

    类型为“指向cv1 void的指针”的prvalue可以转换为类型为“指向cv2 T的指针”的prvalue,其中T是对象类型,cv2与cv1相同,或者cv-qualification与cv1相同 . 如果原始指针值表示存储器中字节的地址A而A不满足T的对齐要求,则未指定结果指针值 . 否则,如果原始指针值指向对象a,并且存在类型为T(忽略cv-qualification)的对象b,该对象b是指针可互换的,则结果是指向b的指针 . 否则,转换指针值不变 .

    指针可互换的定义是:

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

    所以在原始代码中, ss.x 是指针可互换的,因此 (int &)s 实际上指定了 s.x .

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

  • 5

    我认为这是expr.reinterpret.cast#11

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

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

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

    来自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
    

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

相关问题