【问题标题】:Is the aliasing rule symmetric?别名规则是否对称?
【发布时间】:2011-01-21 13:22:04
【问题描述】:

我在 IRC 上与某人进行了讨论,然后出现了这个问题。标准允许我们将int 类型的对象更改为char 左值。

int a;
char *b = (char*) &a;
*b = 0;

如果我们知道对齐没问题,我们是否可以在相反的方向执行此操作?

我看到的问题是,如果将别名规则视为非对称关系,则别名规则不涵盖以下简单情况

int a;
a = 0;

原因是,每个对象都包含一系列sizeof(obj)unsigned char 对象(称为“对象表示”)。如果我们更改int,我们将更改部分或全部这些对象。但是,别名规则仅规定我们可以将int 更改为charunsigned char,但不能反过来。另一个例子

int a[1];
int *ra = a;
*ra = 0;

3.10/15 只描述了一个方向(“包含...的聚合或联合类型”),但这次我们需要另一种方式(“作为元素或非静态数据成员的类型聚合的类型...")。

是否暗示了另一个方向?这个问题也适用于 C。

【问题讨论】:

  • 您能否添加一些代码来说明“相反方向”的含义?您认为哪些代码可能不被允许?
  • @Rob 我以为我展示了。也许我失败了。可能不允许a = 0 以及*ra = 0。对于“A foo contains bar”的“相反方向”,我的意思是“A bar包含在 foo”中。有什么特别不清楚的?
  • 如果你的意思是,char a='A'; int *pi = (int*)a; *pi='B';,那么我认为开始这样的事情并不安全。

标签: c++ c pointer-aliasing symmetric unsigned-char


【解决方案1】:

别名规则只是说明内存中的任何给定对象都有一个“有效类型”(C99 6.5.7,加上脚注 73),并且对此类对象的任何访问都通过以下之一进行:

  • 与有效类型兼容的类型(constrestrict 等限定符,以及有符号/无符号可能会有所不同)
  • 包含一种此类类型的结构或联合
  • 一种字符类型

有效类型当然没有在高级中指定——它只是一个用于指定别名的构造。但其目的很简单,就是不要使用两种不同的非字符类型访问同一个对象。

所以答案是,是的,你确实可以走另一个方向。

【讨论】:

  • 声称 C99 标准打算说些什么是一个相当大胆的举动,而没有任何参考来支持这种说法,然后得出结论什么在 C 中是合法的。那里的 C99 标准非常明确,您的主张没有任何证据。
【解决方案2】:

标准(C99 6.3.2.3 §7)将这样的指针转换定义为“很好”,转换后的指针将指向相同的地址。 (除非 CPU 具有使强制转换无法进行的对齐,否则它是未定义的行为。)

也就是说,实际的演员阵容本身就很好。如果您开始操作数据会发生什么...现在这是另一个由实现定义的故事。

以下来自标准:

“指向对象或不完整类型的指针可能会转换为指向不同对象或不完整类型的指针。如果生成的指针未正确对齐 (57) 指向的类型,则行为未定义。否则,当再次转换回来时,结果应与原始指针比较。

当指向对象的指针转换为指向字符类型的指针时,结果指向对象的最低寻址字节。结果的连续递增,直到对象的大小,产生指针 到对象的剩余字节。”

"57) 一般来说,“正确对齐”的概念是可传递的:如果指向类型 A 的指针正确对齐指向类型 B 的指针,而指向类型 B 的指针又正确对齐指向类型 C 的指针,那么指向类型 A 的指针是 为指向 C 类型的指针正确对齐。"

【讨论】:

    【解决方案3】:

    我想我对这个问题有点困惑,但第二个和第三个示例是通过具有对象类型的左值访问 int(示例中为int)。

    C++ 3.10/15 声明它是第一项,可以通过具有“对象的动态类型”类型的左值访问对象。

    我对这个问题有什么误解?

    【讨论】:

    • 我的意思是,在int a[1]; 中,当我们执行a[0] = 0; 时,我们确实会更改两个对象的存储值。第一个的类型为int,第二个的类型为int[1]。再举一个例子,在struct A { int a; }; 中,当我们执行A a; a.a = 0; 时,我们更改了两个对象的存储值。第一个对象的类型为int,第二个对象的类型为A。存在别名规则允许我们在相反的方向上执行此操作(允许通过聚合左值更改元素或成员),但不是在这个方向上。这就是我要问的。
    • @Johannes:我想我现在明白了这个问题(但仍不完全确定)。但是,我仍然认为标准没有歧义。 a[0] = 0(或a.a = 0 正在通过动态类型(int)访问左值,因此它是明确定义的行为。通过int[1](或struct A)类型的后续访问必须反映这一点更新值(由于标准的抽象机器定义)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-11
    • 2016-10-09
    • 2021-12-10
    • 1970-01-01
    • 2019-09-05
    • 2016-02-24
    相关资源
    最近更新 更多