gpt4 book ai didi

c - 严格的别名规则是什么?

转载 作者:太空宇宙 更新时间:2023-11-04 04:26:10 26 4
gpt4 key购买 nike

当询问common undefined behavior in C时,人们有时会提到严格的别名规则。
他们在说什么?

最佳答案

一个典型的情况是,当将结构(如设备/网络消息)覆盖到系统字大小的缓冲区(如指向uint32_ts或uint16_ts的指针)上时,会遇到严格的别名问题。当您将结构覆盖到这样的缓冲区上,或者通过指针转换将缓冲区覆盖到这样的结构上时,您很容易违反严格的别名规则。
所以在这种情况下,如果我想向某个对象发送消息,我必须有两个不兼容的指针指向同一块内存。我可能会天真地编写这样的代码:

typedef struct Msg
{
unsigned int a;
unsigned int b;
} Msg;

void SendWord(uint32_t);

int main(void)
{
// Get a 32-bit buffer from the system
uint32_t* buff = malloc(sizeof(Msg));

// Alias that buffer through message
Msg* msg = (Msg*)(buff);

// Send a bunch of messages
for (int i =0; i < 10; ++i)
{
msg->a = i;
msg->b = i+1;
SendWord(buff[0]);
SendWord(buff[1]);
}
}

严格的别名规则使此设置非法:取消引用为不属于 compatible type或C 2011 6.5第71段允许的其他类型之一的对象命名的指针是未定义的行为。不幸的是,您仍然可以这样编写代码,可能会收到一些警告,让它编译得很好,结果在运行代码时出现奇怪的意外行为。
(GCC给出别名警告的能力似乎有些不一致,有时给出友好警告,有时则没有。)
要了解此行为未定义的原因,我们必须考虑严格别名规则购买编译器的原因。基本上,使用这个规则,它不必考虑插入指令来刷新 buff循环的每次运行的内容。相反,在优化时,如果对别名进行一些令人恼火的非强制假设,它可以省略这些指令,在循环运行之前将 buff[0]buff[1]加载到CPU寄存器中,并加快循环的速度。在引入严格的别名之前,编译器必须处于一种偏执的状态,即 buff的内容可以随时由任何人从任何地方更改。因此,为了获得额外的性能优势,并且假设大多数人不键入双关指针,引入了严格的别名规则。
请记住,如果您认为示例是人为设计的,那么如果您将缓冲区传递给另一个为您执行发送操作的函数(如果您已经这样做了的话),甚至可能会发生这种情况。
void SendMessage(uint32_t* buff, size_t size32)
{
for (int i = 0; i < size32; ++i)
{
SendWord(buff[i]);
}
}

并重写前面的循环以利用这个方便的函数
for (int i = 0; i < 10; ++i)
{
msg->a = i;
msg->b = i+1;
SendMessage(buff, 2);
}

编译器可能无法或可能无法或智能到尝试内联SendMessage,并且可能决定再次加载或不加载buff。如果 SendMessage是另一个单独编译的API的一部分,那么它可能有加载buff内容的指令。然后,也许你在C++中,这是编译器认为它可以内嵌的一些模板头的实现。或者可能只是你为了方便在.c文件中写的东西。无论如何,不确定的行为可能还会发生。即使我们知道一些在幕后发生的事情,这仍然是违反规则的,因此没有明确定义的行为是可以保证的。因此,仅仅通过包装一个接受单词分隔缓冲区的函数并不一定有帮助。
那我该怎么办呢?
使用工会。大多数编译器都支持这一点,而不会抱怨严格的别名。这在C99中是允许的,在C11中是明确允许的。
union {
Msg msg;
unsigned int asBuffer[sizeof(Msg)/sizeof(unsigned int)];
};

可以在编译器中禁用严格别名(gcc中为 f[no-]strict-aliasing
您可以使用 char*作为别名,而不是系统的单词。规则允许 char*的异常(包括 signed charunsigned char)。通常认为 char*会给其他类型起别名。但是,这不会以另一种方式起作用:没有假设您的结构会给字符缓冲区起别名。
新手当心
当两种雷场叠加在一起时,这只是一个潜在雷场。您还应该了解 endiannessword alignment,以及如何通过 packing structs正确处理对齐问题。
脚注
1 C 2011 6.5 7允许左值访问的类型有:
与对象的有效类型兼容的类型,
与对象的有效类型兼容的类型的限定版本,
与对象的有效类型相对应的有符号或无符号类型,
一种类型,它是与对象的有效类型的限定版本相对应的有符号或无符号类型,
在其成员(递归地包括子聚合或包含的联合的成员)中包含上述类型之一的聚合或联合类型,或
字符类型。

关于c - 严格的别名规则是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41145460/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com