【问题标题】:Does the following code violate strict aliasing?下面的代码是否违反了严格的别名?
【发布时间】:2019-01-19 15:45:51
【问题描述】:

以下代码是否违反严格别名?

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

为什么不呢?因为我们最终会使用合法的int * 取消引用 int a 的指针

为什么是?因为我们将 char * 转换为 int * 并取消引用它(int *),这似乎是一个严格的别名违规

【问题讨论】:

  • AFAIR 可以使用char * 访问任何对象,而不会违反严格的别名规则。
  • 为什么你认为 char * 在这段代码中的某个时候被取消引用了?
  • 是的,但另一种方式(使用int * 别名char *)是有问题的

标签: c strict-aliasing


【解决方案1】:

严格的别名规则不关心中间转换。他们只关心最终用于访问对象的指针的类型,以及对象本身的原始类型(技术上是它的“有效类型”,但现在这并不重要)。

在您的示例代码中,您使用int 的地址。结果的类型为int *。您将该指针转换为char *,然后再次将其转换为int *,然后才取消引用它。访问时使用的指针类型为int *,指向的对象类型为int,所以严格的别名规则没有问题。

您是正确的,严格的别名规则相对于char 是不对称的,但这仅在对象本身的类型为char 或访问中使用的指针类型为char 时才重要:

char x[sizeof(int)] = { 0 };
*(int *)x = 1;  // undefined behavior

int y = 1234;
*(char *)y = 0; // valid; value of y becomes unspecified

理论上,两个指针类型之间的转换可能会丢失信息,但从其他类型转换为char * 并再次返回时不会。此外,这仅适用于您现在不太可能遇到的计算机。我真的不记得一个例子了。

【讨论】:

    【解决方案2】:

    此代码有效。如果不存在对齐问题,则允许在两种对象指针类型之间转换并返回,并且明确允许转换为 char * 以访问对象表示(即读取单个字节)。

    C standard 第 6.3.2.3p7 节指出:

    指向对象类型的指针可以转换为指向对象类型的指针 不同的对象类型。如果结果指针不正确 为引用类型对齐,则行为未定义。 否则,当再次转换回来时,结果将比较 等于原来的指针。当指向对象的指针是 转换为指向字符类型的指针,结果指向 对象的最低寻址字节。的连续递增 结果,直到对象的大小,产生指向剩余对象的指针 对象的字节数。

    由于您从int * 转换为char *,然后再返回int *,因此这里没有严格的别名违规。

    【讨论】:

    • If the resulting pointer is not correctly aligned for the referenced type 如何知道两个对象是否正确对齐? (不是关于这篇文章中的具体问题,而是一般来说)它们的大小的模是否为零?
    • @user2162550 对齐是实现定义的,但一般来说,基本类型的起始地址是其大小的倍数。数组将与基类型具有相同的对齐方式,而结构将具有与最大成员的基类型相同的对齐方式。
    【解决方案3】:

    不,这不是违规。

    因为我们将 char * 转换为 int *

    您错过了您提到的char * 实际上是int * 的部分。因此,最终通过指向int 的指针访问int 类型——这是完全有效的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-09
      • 1970-01-01
      相关资源
      最近更新 更多