使用void *键入punning而不破坏C99中的严格别名规则

时间:2013-04-01 14:10:11

标签: c c99 void-pointers strict-aliasing type-punning

我最近遇到了严格的别名规则,但我无法理解如何使用void *执行类型惩罚而不违反规则。

我知道这违反了规则:

int x = 0xDEADBEEF;

short *y = (short *)&x;
*y = 42;

int z = x;

而且我知道我可以安全地在C99中使用联合来进行打字:

union{
    int x;
    short y;
} data;

data.x = 0xDEADBEEF;
data.y = 42;

int z = data.x;

但是如何使用void *在C99中安全地执行打字?以下是正确的:

int x = 0xDEADBEEF;

void * helper = (void *)&x;

short *y = (short *)helper;
*y = 42;

int z = x;

我怀疑代码仍然会破坏严格的别名规则,因为变量x地址的内存可以被x和解除引用的y修改。

如果通过void *未定义类型 - 双关语,那么C99中void *的目的是什么?

1 个答案:

答案 0 :(得分:19)

void *与类型惩罚无关。其主要目的是:

  1. 允许通用分配和释放操作,而不关心调用者在那里存储的对象类型(例如mallocfree)。

    < / LI>
  2. 允许调用者通过函数将指针传递给任意类型,该函数将通过回调将其传回(例如qsortpthread_create)。在这种情况下,编译器不能强制执行类型检查;在编写调用者和回调时,你的责任确保回调访问具有正确类型的对象。

  3. 指向void的指针也用于实际操作对象的几个地方(如memcpy),作为对象的重叠unsigned char []表示。这可以被视为类型惩罚,但它不是别名违规,因为char类型允许别名来访问其表示。在这种情况下,unsigned char *也可以使用,但void *的优势在于指针会自动转换为void *

    在您的示例中,由于原始类型为int而不是联合,因此没有合法的方式来输入-pen并将其作为short进行访问。您可以将x的值复制到联合,在那里执行明确定义的类型惩罚,然后将其复制回来。一个好的编译器应该完全省略副本。或者,您可以将写入分解为char次写入,然后这将是合法的别名。