问题描述
-fno-strict-aliasing
添加到发布版本的额外标志中,但是我不明白为什么他们不希望为...启用严格别名性能。有人在您不想在C语言中使用严格的别名的情况下很好吗?
@H_502_0@还,这是否意味着如果我们打破严格混叠规则,但告诉编译器不要进行任何严格混叠优化,这不是未定义的行为吗?
@H_502_0@谢谢
解决方法
...当不想启用严格的别名时
严格的混叠是C标准设置的一项要求(或许多要求)。因此,符合该标准的C代码必须遵守该标准设置的(严格)别名规则。
编译器可以使用这些规则来优化生成的代码。如果某些C代码违反了标准别名规则,则编译器可能会由于这种优化而生成行为异常的代码。大多数编译器都可以选择根据别名规则关闭优化。
因此答案是:如果您的代码违反了“严格别名”规则,则可以告诉编译器不要基于别名规则进行优化。
这引发了一个新问题:为什么要编写违反别名规则的代码?
一个原因可能是性能。换句话说-如果您确切地知道系统在发生违规情况下的行为,并且通过执行违规操作可以使代码性能更好,那么您可能要说:我更喜欢性能而不是标准合规性。
我看到的一个例子是(网络)数据包校验和的计算。例如,保存数据包的结构可以包含许多不同的字段,例如mac,ip等,但是要计算某种校验和,您可能希望将数据包视为整数数组。使用uint32_t * p = &packet
之类的代码很容易做到。它违反了别名规则,但可能会在目标系统上正常工作,因为编译器不会根据严格的别名规则进行优化。
另一个原因可能是代码可读性。为了避免违反别名规则,您通常需要编写“一些额外的代码”,例如将事物放入并集,进行移位和逻辑或计算int值等。有些人认为这样的代码难以读取和维护,因此他们更喜欢通过违反别名规则来“编写更简单的代码”(因此在编译器中将其关闭)。
,理想情况下,您始终会使用严格的别名。不幸的是,别名规则很复杂。结果,大多数代码在编写时都没有考虑严格的别名,如果启用了该优化,则会破坏代码。查看任何C项目,您可能会发现一些可疑的指针转换,然后进行取消引用。
现实是,对于大多数代码,不使用严格的别名,而仅对您自己验证为正确的对性能要求最高的代码启用它,这是最安全的。
,鉴于clang和gcc的维护者不费力气处理标准所要求的所有混淆情况(他们将某些棘手的情况视为标准中的缺陷而不是其编译器中的缺陷),也没有为了精确地指定应该或不应该可靠地处理的情况子集,我建议编写代码的方式应尽可能减少禁用别名导致的性能损失,然后记录处理代码的要求与-fno-strict-aliasing
。否则,即使代码似乎在今天能正常工作,也无法知道clang和gcc的作者是否会承担避免避免将来版本破坏它的义务。
请注意,当clang和gcc发生故障时,很多特殊情况都涉及到诸如写入具有新类型数据的存储,这些数据的位模式恰好与现有数据匹配。在这种情况下,clang和gcc倾向于优化写操作,而不会记住写操作更改了所讨论存储的有效类型。可以肯定的是,在大多数情况下,代码可能会写入位模式与已保存的存储相匹配的数据,clang和gcc不会优化写入并丢失对有效类型的更改,但是我不知道关于可以保证他们不会这样做。
更糟糕的是,某些极端情况涉及这样的情况,即即使代码无法执行,代码也可能违反gcc对“严格别名规则”的解释,足以使它跳入歧途。
例如,给定功能:
long test(long *p1,long long *p2,int mode)
{
*p1 = 1;
if (mode)
*(long*)p2 = 2;
else
*p2 = 2;
return *p1;
}
x86-64 gcc 10.2生成的代码即使mode
为1,也将忽略将值2存储到*(long*)p2
可能影响p1值的可能性。
某些代码(如SWIG生成的用于在C和许多脚本语言之间生成绑定的代码)违反了所有别名规则。必须使用没有严格的别名标志进行编译,否则将无效。
,与上面声称的相反,任何版本的 C 标准都不需要严格别名,但某些编译器会选择使用严格别名。而且不一定是好的选择。 Linux 关闭严格别名的原因是它干扰了 Linux 内核和其他地方使用的标准 C 编程方法,特别是所谓的“类型双关”。一个明显的例子是任何类型的内存分配器,其中潜在的任何类型的释放对象然后被再次分配为任何类型。例如。 "x = mymalloc(100); ... myfree(x); .... y = myalloc(100);
"在这里,myfree 获取某种类型的对象,例如一个 100 个字符的数组,将其放入已释放内存的内部队列中,例如某个链表元素,然后甚至可以将其与相邻的可用内存将其分配为不同对象的一部分,例如 200 个浮点数的数组。 K&R 书的 ANSI 版本有一个与严格别名不兼容的 malloc 实现示例,丹尼斯·里奇(Dennis Ritchie)很有说服力地认为,这种类型的编译器“优化”既危险又实用性有限。
当然,我可能是错的 - 欢迎任何声称严格别名是强制性的人引用一些强制要求严格别名的 C 标准的规定。他们只能引用一项规定,其中某种别名被定义为“未定义的行为”,根据对当前标准的一些解释允许 编译器使用诸如严格别名之类的东西。