c++ - 它是 gcc -O2 优化错误(与 -O1 的结果不同)吗?
问题描述
我写了一个非常简单的程序,它表现正常,没有-O2
:
#include <stdio.h>
#include <stdint.h>
int main()
{
uint32_t A[4] = { 1, 2, 3, 4 };
float B[4] = { 0, 0, 0, 0 };
float C[4] = { 5, 6, 7, 8 };
int i;
// convert integer A to float B
for (i = 0; i < 4; i++)
B[i] = (float)A[i];
// memory copy from B to C
uint32_t *src = (uint32_t*)(B);
uint32_t *dst = (uint32_t*)(C);
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[3] = src[3];
#if 0
// open this to correct the error
__asm__("":::"memory");
#endif
// print C, C should be [1.0, 2.0, 3.0, 4.0]
for (i = 0; i < 4; i++)
printf("%f\n", C[i]);
return 0;
}
编译没有-O2
:
$ gcc error.c -o error
$ ./error
1.0000
2.0000
3.0000
4.0000
它按预期工作。但是如果我添加了一个-O2
:
$ gcc -O2 error.c -o error
$ ./error
-6169930235904.000000
0.000000
-6169804406784.000000
0.000000
此外,如果您切换#if 0
到#if 1
,它会再次正常工作。在asm ("":::"memory")
同一个线程中应该是不必要的。
是-O2
优化的bug吗??
有什么我可以告诉编译器照顾它的吗?我有一个将 xmm 寄存器存储到 (void*) 指针的函数,例如:
inline void StoreRegister(void *ptr, const __m128& reg)
{
#if DONT_HAVE_SSE
const uint32_t *src = reinterpret_cast<const uint32_t*>(®);
uint32_t *dst = reinterpret_cast<uint32_t*>(ptr);
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[3] = src[3];
#else
_mm_storeu_si128(reinterpret_cast<__m128*>(ptr), _mm_castps_si128(reg));
#endif
}
这dst
是C
上面代码中的,任何在不修改函数签名的情况下使其正确的方法。
解决方案
不,这不是编译器错误的表现。
相反,由于您使用 cast &c的结果,您的代码的行为是未定义的。(uint32_t*)(B)
这违反了严格的别名。
在处理未定义的结构时,编译器——尤其是 gcc——变得越来越激进。标准允许它们假设未定义的行为不会发生,并且可以删除包含它的任何分支。
推荐阅读
- json - 配置json解析器解析json中转义的json字符串
- java - 从 ObservableList 填充的 tableView(JavaFX) 不起作用
- ios - 如何获取特定元素的所有后代?
- reactjs - 表单未在模态 React-Bootstrap 中呈现
- c# - c# 反序列化 JSON 文件中的派生类
- spring-cloud-sleuth - 使用 @SpanTag 标记 Spring sleuth span 的值不提供添加多个键值对的映射
- python-3.x - 我们怎样才能找到这条曲线的频率?
- python - Python 中 Pandas 的索引 + 匹配等价物
- python - 熊猫有效地搜索匹配条件的第一行
- ibm-datapower - 收到特定错误代码时如何处理 DataPower 策略规则中的错误