C++中的严格别名规则和类型别名

use*_*999 6 c++ strict-aliasing language-lawyer type-punning

我试图在违反严格别名规则时掌握未定义的行为.我已经阅读了很多关于SO的文章以便理解它.但是,还有一个问题:我真的不明白两种类型的非法别名.cpp-reference状态:

键入别名

每当尝试通过类型为AliasedType的glvalue读取或修改DynamicType类型的对象的存储值时,除非满足下列条件之一,否则行为是未定义的:

  • AliasedType和DynamicType类似.
  • AliasedType是DynamicType的(可能是cv限定的)有符号或无符号变体.
  • AliasedType是std :: byte,(自C++ 17开始)char或unsigned char:这允许将任何对象的对象表示检查为字节数组.

我还在SO上找到了一个很好的例子,我清楚地看到了这个问题:

int foo( float *f, int *i ) { 
    *i = 1;               
    *f = 0.f;            

   return *i;
}

int main() {
    int x = 0;

    std::cout << x << "\n";   // Expect 0
    x = foo(reinterpret_cast<float*>(&x), &x);
    std::cout << x << "\n";   // Expect 0?
}
Run Code Online (Sandbox Code Playgroud)

int并且float是不相似的类型,这个程序可能会造成严重破坏.我未能看到和理解的是以下修改:

struct A
{
    int a;
};

struct B
{
    int b;
};

A foo( A *a, B *b ) { 
    a->a = 1;               
    b->b = 0;            

    return *a;
}

int main() {
    A a;
    a.a = 0;


    std::cout << a.a << "\n";   // Expect 0
    a = foo(&a, reinterpret_cast<B*>(&a));
    std::cout << a.a << "\n";   // Expect 0?
}
Run Code Online (Sandbox Code Playgroud)

AB类似的类型和一切都很好,或者他们是非法的别名,我有未定义的行为.如果它是合法的,这是因为A并且B是聚合(如果是的话,我必须改变什么才能使它成为未定义的行为)?

任何单挑和帮助都将非常感激.

编辑 关于重复的问题

我知道这篇文章,但我不知道他们在哪里澄清哪些类型是相似的.至少我不理解它.因此,如果你不关闭这个问题,那就太好了.

bol*_*lov 2

不,这是不合法的,并且您有未定义的行为:

\n\n
\n

8.2.1 值类别[basic.lval]

\n\n

11 如果程序尝试通过除下列类型之一之外的泛左值来访问对象的存储值,\n 行为是未定义的:63

\n\n

(11.1) \xe2\x80\x94 对象的动态类型,

\n\n

(11.2) \xe2\x80\x94 对象动态类型的 cv 限定版本,

\n\n

(11.3) \xe2\x80\x94 与对象的动态类型相似的类型(如 7.5 中定义),

\n\n

(11.4) \xe2\x80\x94 是与对象的动态类型相对应的有符号或无符号类型,

\n\n

(11.5) \xe2\x80\x94 是与对象动态类型的 cv 限定版本相对应的有符号或无符号类型,

\n\n

(11.6) \xe2\x80\x94 聚合或联合类型,在其元素或非静态数据成员中包含上述类型之一(递归地包括子聚合的元素或非静态数据成员)或包含联合),

\n\n

(11.7) \xe2\x80\x94 是对象动态类型的(可能是 cv 限定的)基类类型,

\n\n

(11.8) \xe2\x80\x94 char、unsigned char 或 std::byte 类型

\n\n
\n\n

63) 此列表的目的是指定对象可以使用或不使用别名的情况。

\n
\n