22

我最近遇到了严格的别名规则,但我无法理解如何在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

如果 type-punning 未定义 via ,那么C99void *中的目的是什么?void *

4

1 回答 1

22

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

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

  2. 允许调用者通过函数传递指向任意类型的指针,该函数将通过回调将其传回(例如qsortand pthread_create)。在这种情况下,编译器无法强制进行类型检查;在编写调用者和回调时,您有责任确保回调访问具有正确类型的对象。

指向的指针void也用于一些memcpy实际操作对象的地方(如 ),作为对象的覆盖unsigned char []表示。这可以看作是类型双关语,但这不是别名违规,因为char允许类型对任何内容进行别名以访问其表示。在这种情况下,unsigned char *也可以使用,但void *具有指针自动转换为void *.

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

于 2013-04-01T14:14:05.090 回答