简体   繁体   English

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

[英]Type punning with void * without breaking the strict aliasing rule in C99

I recently came across the strict aliasing rule, but I'm having trouble understanding how to use void * to perform type punning without breaking the rule. 我最近遇到了严格的别名规则,但我无法理解如何使用void *来执行类型惩罚而不违反规则。

I know this breaks the rule: 我知道这违反了规则:

int x = 0xDEADBEEF;

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

int z = x;

And I know that I can safely use a union in C99 for type-punning: 而且我知道我可以安全地在C99中使用联合来进行类型惩罚:

union{
    int x;
    short y;
} data;

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

int z = data.x;

But how do I use void * to safely perform type-punning in C99? 但是如何在C99中使用void *来安全地执行类型惩罚呢? Is the following correct: 以下是正确的:

int x = 0xDEADBEEF;

void * helper = (void *)&x;

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

int z = x;

I suspect that code will still break the strict aliasing rule since the memory at variable x 's address can be modified by both x and a dereferenced y . 我怀疑代码仍会破坏严格的别名规则,因为变量x地址的内存可以被x和解除引用的y

If type-punning is undefined via void * , what is the purpose of the void * in C99? 如果通过void *未定义类型 - 双关语,那么C99中void *的目的是什么?

void * has nothing to do with type-punning. void *与类型惩罚无关。 Its main purposes are: 其主要目的是:

  1. To allow for generic allocation and freeing operations that don't care about the type of the object the caller is storing there (eg malloc and free ). 允许通用分配和释放操作,而不关心调用者在那里存储的对象的类型(例如mallocfree )。

  2. To allow a caller to pass a pointer to an arbitrary type through a function that will pass it back via a callback, (eg qsort and pthread_create ). 允许调用者通过函数将指针传递给任意类型,该函数将通过回调将其传回(例如qsortpthread_create )。 In this case, the compiler cannot enforce type checking; 在这种情况下,编译器不能强制执行类型检查; it's your responsibility when writing the caller and callback to ensure that the callback accesses the object with the correct type. 在编写调用者和回调时, 您有责任确保回调访问具有正确类型的对象。

Pointers to void are also used in a few places (like memcpy ) that actually operate on an object as the overlaid unsigned char [] representation for the object. 指向void指针也用于实际操作对象的一些地方(如memcpy ),作为对象的重叠unsigned char []表示。 This could be seen as type-punning, but it's not an aliasing violation because char types are allowed to alias anything to access its representation. 这可以被视为类型惩罚,但它不是别名冲突,因为允许使用char类别来访问其表示的任何内容。 In this case, unsigned char * would also work, but void * has the advantage that pointers automatically convert to void * . 在这种情况下, unsigned char *也可以工作,但void *的优点是指针会自动转换为void *

In your example, since the original type is int and not a union, there is no legal way to type-pun and access it as short . 在您的示例中,由于原始类型是int而不是union,因此没有合法的方式来输入pun并将其作为short访问。 You could instead copy the value of x to a union, perform well-defined type-punning there, then copy it back. 您可以将x的值复制到union,在那里执行明确定义的类型 - 惩罚,然后将其复制回来。 A good compiler should omit the copy entirely. 一个好的编译器应该完全省略副本。 Alternatively, you could break the write down into char writes and then it would be legal aliasing. 或者,您可以将写入分解为char写入,然后它将是合法别名。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM