我有一个类,它有 2 个指向外部存储器的指针 p_Data 和 p_DataWrite。大多数时候,这两个指针都指向同一内存,并用于读取所述内存(p_Data)或写入所述内存(p_DataWrite)。我现在有一个情况,我写入内存(使用 p_DataWrite),然后读取内存(使用 p_Data)。当我使用 O2 在 Linux 的 ARMv7 平台上使用 clang++ 编译此代码时,我得到的效果是首先读取内存,然后写入内存。我尝试使用p_Data指针写入内存,效果没有了。这不是该项目的选择。
我只看到至少具有 O2 的 ARMv7 Linux 的效果。我还为 x86_64 Linux 和 x64 Windows 构建了我的项目,并且可以使用 O2 及更高版本进行编译,而不会出现此问题。
如何告诉编译器/优化器这两个指针是“相同的”并且不允许更改执行顺序?
编辑添加示例代码:
*((unsigned int *)IN_Class.p_DataUserWrite) = 0x12345678;
unsigned short In_Word = *((unsigned short *)IN_Class.p_DataUser + 0);
unsigned short Out_Word = (unsigned short)((In_Word >> 8) | (In_Word << 8));
In_Word = *((unsigned short *)IN_Class.p_DataUser + 1);
*((unsigned short *)OUT_CLass.p_DataUserWrite + 1) = Out_Word;
Out_Word = (In_Word >> 8) | (In_Word << 8);
*((unsigned short *)OUT_CLass.p_DataUserWrite) = Out_Word;
翻译为
; *((unsigned int *)IN_Class.p_DataUserWrite) = 0x12345678;
1f2b8: e5923034 ldr r3, [r2, #0x34]
1f2bc: e5920030 ldr r0, [r2, #0x30]
; *((unsigned short *)OUT_CLass.p_DataUserWrite + 1) = Out_Word;
1f2c0: e5911030 ldr r1, [r1, #0x30]
; unsigned short In_Word = *((unsigned short *)IN_Class.p_DataUser + 0);
1f2c4: e1d320b0 ldrh r2, [r3]
; In_Word = *((unsigned short *)IN_Class.p_DataUser + 1);
1f2c8: e1d330b2 ldrh r3, [r3, #2]
; *((unsigned short *)OUT_CLass.p_DataUserWrite + 1) = Out_Word;
1f2cc: e6bf2fb2 rev16 r2, r2
1f2d0: e1c120b2 strh r2, [r1, #2]
1f2d4: e3052678 movw r2, #0x5678
1f2d8: e3412234 movt r2, #0x1234
; *((unsigned int *)IN_Class.p_DataUserWrite) = 0x12345678;
1f2dc: e5802000 str r2, [r0]
; *((unsigned short *)OUT_CLass.p_DataUserWrite) = Out_Word;
1f2e0: e6bf0fb3 rev16 r0, r3
1f2e4: e1c100b0 strh r0, [r1]
; }
1f2e8: e12fff1e bx lr
使用
-fno-strict-aliasing
进行编译。
在
*((unsigned int *)IN_Class.p_DataUserWrite) = 0x12345678;
中,您使用类型 unsigned int
写入地址。这与其他行中用于访问地址的类型不同,其中使用 unsigned short
。
使用 C++ 2020 7.2.1 [basic.lval] 11 中列出的两种不同类型访问同一内存违反了该段落中的别名规则。那么该行为不是由 C++ 标准定义的。其重要性在于,编译器不必将访问视为
unsigned int
并将访问视为 unsigned short
,就好像它们可能访问相同的内存一样。因此优化器可以自由地重新排列此代码,就好像地址不同一样。
Clang 有一个功能可以告诉编译器支持不同类型的别名内存,并且
-fno-strict-aliasing
开关要求这样做。
或者,您可以修改代码以仅使用
unsigned short
来访问内存,将 0x12345678
的写入分为两次 unsigned short
的写入。