如何强制C中未使用的内存读取不会被优化? [英] How to force an unused memory read in C that won't be optimized away?

查看:237
本文介绍了如何强制C中未使用的内存读取不会被优化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

微控制器通常需要读取寄存器才能清除某些状态。在C中是否有便携式方法,以确保如果不使用数据,则读取不会被优化?指向内存映射寄存器的指针是否被声明为volatile?换句话说,以下是否符合标准的编译器?

  void func(void)
{
volatile unsigned int * REGISTER =(volatile unsigned int *)0x12345678;

* REGISTER;
}

我明白处理像这样的功能会依赖于编译器的问题。所以在这种情况下,我对便携式的定义有点松动。我只是意味着它将尽可能广泛地与最受欢迎的工具链一起工作。

解决方案

关于什么 volatile 意味着什么。我认为大多数人都同意你所展示的这个结构是为了做你想做的事情,但是没有一般的一致认为,C标准中的语言实际上保证了它/ C99。 (C2011中的情况可能已经有所改善;我还没有读过)。



非标准但是嵌入式编译器相当广泛的支持,可能更多可能工作的是

  void func(void)
{
asm volatile(:: r(*(unsigned int *)0x12345678));
}

('volatile'这里适用于'asm',意思是'即使没有输出操作数也不会被删除,也不需要将它放在指针上。)



这个结构的主要缺点是您仍然不能保证编译器将生成一个单指令内存读取。使用C2011,使用 _Atomic unsigned int 可能足够,但是在没有该功能的情况下,您几乎必须写一个真实的(非空的)如果你需要这个保证,装配会自动插入。



编辑:今天早上我又发现了一个皱纹。如果从内存位置读取具有更改该内存位置值的副作用,则需要

  void func(void )
{
unsigned int * ptr =(unsigned int *)0x12345678;
asm volatile(:= m(* ptr):r(* ptr));
}

,以防止对该位置的其他读取进行错误优化。 (为了100%清楚,这个更改不会改变为 func 本身生成的汇编语言,但可能会影响周围代码的优化,特别是如果 func 是内联的。)


Microcontrollers often require a register to be read to clear certain status conditions. Is there a portable way in C to ensure that a read is not optimized away if the data is not used? Is it sufficient that the pointer to the memory mapped register is declared as volatile? In other words, would the following always work on standard compliant compilers?

void func(void)
{
   volatile unsigned int *REGISTER = (volatile unsigned int *) 0x12345678;

   *REGISTER;
}

I understand that dealing with functionality like this runs into compiler-dependent issues. So, my definition of portable is a bit loose in this case. I just mean that it would work as widely as possible with the most popular toolchains.

解决方案

People argue quite strenuously about exactly what volatile means. I think most people agree that the construct you show was intended to do what you want, but there is no general agreement that the language in the C standard actually guarantees it as of C99. (The situation may have been improved in C2011; I haven't read that yet.)

A nonstandard, but fairly widely supported by embedded compilers, alternative that may be more likely to work is

void func(void)
{
  asm volatile ("" : : "r" (*(unsigned int *)0x12345678));
}

(The 'volatile' here appies to the 'asm' and means 'this may not be deleted even though it has no output operands. It is not necessary to put it on the pointer as well.)

The major remaining drawback of this construct is that you still have no guarantee that the compiler will generate a one-instruction memory read. With C2011, using _Atomic unsigned int might be sufficient, but in the absence of that feature, you pretty much have to write a real (nonempty) assembly insert yourself if you need that guarantee.

EDIT: Another wrinkle occurred to me this morning. If reading from the memory location has the side-effect of changing the value at that memory location, you need

void func(void)
{
  unsigned int *ptr = (unsigned int *)0x12345678;
  asm volatile ("" : "=m" (*ptr) : "r" (*ptr));
}

to prevent mis-optimization of other reads from that location. (To be 100% clear, this change will not change the assembly language generated for func itself, but may affect optimization of surrounding code, particularly if func is inlined.)

这篇关于如何强制C中未使用的内存读取不会被优化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆