首页 文章

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

提问于
浏览
18

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

  • 19

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

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

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

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

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

相关问题