c - 在不违反 C99 中严格的别名规则的情况下使用 void * 输入双关语

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

我最近遇到了严格的别名规则,但我很难理解如何在不违反规则的情况下使用 void * 执行类型双关。

我知道这违反了规则:

int x = 0xDEADBEEF;

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

int z = x;

而且我知道我可以安全地使用 C99 中的 union 来进行类型双关:

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 * 的目的是什么?

最佳答案

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

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

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

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

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

关于c - 在不违反 C99 中严格的别名规则的情况下使用 void * 输入双关语,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15745030/

相关文章:

c++ - 如何使用 FILE* 写入内存缓冲区?

GCC 可以警告我修改 C99 中 const 结构的字段吗?

iphone - libSystem 库的引用

c - 有什么方法可以在 C 中执行这个 void ptr 的 "cast"到结构指针内联?

c++ - 函数参数中的空指针

c - PThread Create 不创建线程

c - 嵌入式设备与远程服务器通信的协议(protocol)架构

c - 在 C 中对命令行参数执行操作

检查将一个函数指针转换为另一个函数指针是否安全

c++ - 一般如何从 void * 指针动态转换?