什么时候 char* 对严格指针别名是安全的? [英] When is char* safe for strict pointer aliasing?

查看:24
本文介绍了什么时候 char* 对严格指针别名是安全的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直试图理解严格的别名规则,因为它们适用于字符指针.

I've been trying to understand the strict aliasing rules as they apply to the char pointer.

此处声明如下:

总是假定 char* 可以指代任何对象的别名.

It is always presumed that a char* may refer to an alias of any object.

好吧,在套接字代码的上下文中,我可以这样做:

Ok so in the context of socket code, I can do this:

struct SocketMsg
{
   int a;
   int b;
};

int main(int argc, char** argv)
{
   // Some code...
   SocketMsg msgToSend;
   msgToSend.a = 0;
   msgToSend.b = 1;
   send(socket, (char*)(&msgToSend), sizeof(msgToSend);
};

但是有这个声明

反之则不然.将 char* 转换为 char* 以外的任何类型的指针并取消引用它通常违反严格的别名规则.

The converse is not true. Casting a char* to a pointer of any type other than a char* and dereferencing it is usually in violation of the strict aliasing rule.

这是否意味着当我接收一个字符数组时,当我知道消息的结构时,我无法重新解释转换为结构体:

Does this mean that when I recv a char array, I can't reinterpret cast to a struct when I know the structure of the message:

struct SocketMsgToRecv
{
    int a;
    int b;
};

int main()
{
    SocketMsgToRecv* pointerToMsg;
    char msgBuff[100];
    ...
    recv(socket, msgBuff, 100);
    // Ommiting make sure we have a complete message from the stream
    // but lets assume msgBuff[0]  has a complete msg, and lets interpret the msg

    // SAFE!?!?!?
    pointerToMsg = &msgBuff[0];

    printf("Got Msg: a: %i, b: %i", pointerToMsg->a, pointerToMsg->b);
}

第二个例子会不会因为基本类型是一个 char 数组而我将它转换为一个结构体而不起作用?在一个严格别名的世界中,您如何处理这种情况?

Will this second example not work because the base type is a char array and I'm casting it to a struct? How do you handle this situation in a strictly aliased world?

推荐答案

回复 @Adam Rosenfield:只要 char* 的供应商开始做类似的事情,联合就会实现对齐.

Re @Adam Rosenfield: The union will achieve alignment so long as the supplier of the char* started out doing something similar.

退后一步弄清楚这是怎么回事可能会很有用.

It may be useful to stand back and figure out what this is all about.

别名规则的基础是编译器可以将不同简单类型的值放在不同的内存边界上以改进访问,并且在某些情况下硬件可能需要这种对齐才能完全使用指针.这也可以出现在具有各种不同大小元素的结构中.该结构可以从一个好的边界开始.此外,编译器可能仍会在结构体内部引入松弛位,以完成需要它的结构体元素的正确对齐.

The basis for the aliasing rule is the fact that compilers may place values of different simple types on different memory boundaries to improve access and that hardware in some cases may require such alignment to be able to use the pointer at all. This can also show up in structs where there is a variety of different-sized elements. The struct may be started out on a good boundary. In addition, the compiler may still introduce slack bites in the interior of the struct to accomplish proper alignment of the struct elements that require it.

考虑到编译器通常有控制所有这些处理方式的选项,您可以看到有很多方式可以发生意外.当将指向结构的指针(转换为 char* 或不转换)传递到编译为期望不同对齐约定的库时,这一点尤其重要.

Considering that compilers often have options for controlling how all of this is handled, or not, you can see that there are many ways that surprises can occur. This is particularly important to be aware of when passing pointers to structs (cast as char* or not) into libraries that were compiled to expect different alignment conventions.

char* 怎么样?

关于 char* 的假设是 sizeof(char) == 1(相对于所有其他相当大的数据的大小)并且 char* 指针没有任何对齐要求.因此,真正的 char* 始终可以安全地传递并成功使用,而无需担心对齐,这适用于 char[] 数组的任何元素,在指针上执行 ++ 和 -- 等等.(奇怪的是,void* 并不完全相同.)

The presumption about char* is that sizeof(char) == 1 (relative to the sizes of all other sizable data) and that char* pointers don't have any alignment requirement. So a genuine char* can always be safely passed around and used successfully without concern for alignment, and that goes for any element of a char[] array, performing ++ and -- on the pointers, and so on. (Oddly, void* is not quite the same.)

现在你应该能够看到如果你将某种结构数据传输到一个本身没有正确对齐的 char[] 数组中,试图转换回一个需要对齐的指针可能是一个严重的问题问题.

Now you should be able to see how if you transfer some sort of structure data into a char[] array that was not itself aligned appropriately, attempting to cast back to a pointer that does require alignment(s) can be a serious problem.

如果你将一个 char[] 数组和一个结构体结合起来,那么最苛刻的对齐方式(即结构体的对齐方式)将被编译器认可.如果供应商和消费者有效地使用匹配的联合,那么这将起作用,以便将 struct* 转换为 char* 并返回正常工作.

If you make a union of a char[] array and a struct, the most-demanding alignment (i.e., that of the struct) will be honored by the compiler. This will work if the supplier and the consumer are effectively using matching unions so that casting of the struct* to char* and back works just fine.

在那种情况下,我希望数据是在指向它的指针被转换为 char* 之前在类似的联合中创建的,或者以任何其他方式作为 sizeof(char) 字节数组传输.确保任何编译器选项在依赖的库和您自己的代码之间兼容也很重要.

In that case, I would hope that the data was created in a similar union before the pointer to it was cast to char* or it was transferred any other way as an array of sizeof(char) bytes. It is also important to make sure any compiler options are compatible between the libraries relied upon and your own code.

这篇关于什么时候 char* 对严格指针别名是安全的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆