我正在处理的嵌入式项目需要读取内存中的特定位置,但不需要该内存位置的值.目前我正在将volatile变量读入虚拟变量,foo1()如下所示,但我很好奇这个方法foo2().
void foo1(void) {
volatile uint32_t *a = (volatile uint32_t *)0xdeadbeef;
volatile uint32_t discard = *a;
}
void foo2(void) {
volatile uint32_t *a = (volatile uint32_t *)0xdeadbeef;
*a;
}
Run Code Online (Sandbox Code Playgroud)
请参阅dissassembly(使用gcc 4.7.2和-O3编译):
foo1:
movl 0xdeadbeef, %eax
movl %eax, -0x4(%rsp)
ret
foo2:
movl 0xdeadbeef, %eax
ret
Run Code Online (Sandbox Code Playgroud)
该方法foo2()似乎工作,但我想知道它是否可以保证工作,并不是我正在使用的编译器版本和优化的副作用.
该关键字volatile告诉编译器一个对象可能会在正常(即编译器可见)程序流范围之外发生更改。因此,编译器一般都会执行这种访问。最后一句指的是如何执行访问,例如字节读取、未对齐读取等。
此外,编译器必须按照程序流给出的顺序执行对此类对象的所有访问。但请注意,它可以自由地重新排序对非易失性对象的访问,并且底层硬件也可能认为不同(编译器可能不知道这一点)。
编译器可能仍会优化对volatile存在且仅在可见代码中修改的对象的访问。对于未获取地址的局部变量(可能还有其他情况)来说也是如此,因为这些变量无法在作用域之外访问。对于您使用的指针,情况并非如此,因为编译器不知道它们指向的对象。
要删除表达式的结果而不发出编译器警告,只需将其转换为void:
volatile uint32_t *vi = ...;
(void)*vi; // this still might be optimized if vi is local
Run Code Online (Sandbox Code Playgroud)
(如果目标是只读的,请添加const。)
有关访问的详细信息,请参阅 gcc文档volatile。符合 C 标准的实现必须提供此信息。
另请注意,底层硬件仍然可能会对访问进行重新排序,除非内存区域使用严格排序/非缓存的访问策略。这是内存映射外设寄存器的典型情况。如果使用高速缓存/MMU,则可能必须相应地设置这些区域。
| 归档时间: |
|
| 查看次数: |
2381 次 |
| 最近记录: |