【问题标题】:volatile uint32_t on cortex-m3cortex-m3 上的 volatile uint32_t
【发布时间】:2012-03-13 09:19:30
【问题描述】:

这是我的代码:

volatile uint32_t value = *((volatile uint32_t *) 0xA0000000); // here `value` is 12498
value *= 2; // here `value` is still 12498
value |= 0x0000001; // still 12498

在我的调试器中分析变量value 时,它在所有行上都具有相同的值。我做错了什么?

【问题讨论】:

  • 也许您的调试器没有正确处理 volatile?
  • 为什么不只使用一些跟踪并检查实际程序的行为,而不是依赖调试器来进行验证。
  • 你用的是什么处理器?
  • 顺便问一下,您是从硬编码地址0xA0000000 中读取一个uint 吗?现在这是什么巧妙的技巧(或者我错过了什么)?
  • @DipSwitch:ARM Cortex M3。

标签: c cortex-m3


【解决方案1】:

也许您的调试器实际上并没有那么好。当我的一个工具似乎无法正常工作时,我总是会对照另一个工具对其进行检查。

尝试用老式的方式调试,用:

volatile uint32_t value = *((volatile uint32_t *) 0xA0000000);
printf ("A:%d\n", value);

value *= 2;
printf ("B:%d\n", value);

value |= 0x0000001;
printf ("C:%d\n", value);

如果printf 不可用,则使用其他输出方法(看起来您可能正在嵌入式空间中工作)。

看看你得到了什么 - 我更倾向于相信printf-debugging而不是调试器。


如果您的问题不是与value 相关,而是与位于0xA0000000 位置的内存有关,那么它按预期工作。

您正在操作局部变量,而不是内存位置。您需要将值写回,例如:

*((volatile uint32_t *) 0xA0000000) = value;

但是,鉴于您使用 volatile,您完全有可能只需要一个指向该位置的变量指针,以便立即反映更改。

如果是这样的话,你需要一些类似的东西:

volatile uint32_t *pValue = (volatile uint32_t *) 0xA0000000;
*pValue *= 2;
*pValue |= 0x00000001;

在这种情况下,内存位置将在每条指令处更改,而不必显式写入值。

【讨论】:

  • 我目前没有printf,因为我正在为嵌入式系统开发。
  • 那么你应该找到另一种方式,例如stackoverflow.com/questions/5165654/cost-of-fprintf/… 并最终对字符缓冲区做一些事情(puts 或输出到串口等)。
  • github.com/dwelch67,寻找 hexstring,我在任何地方都使用它,或者自己制作,八进制更容易,但我们大多数人仍在工作以十六进制而不是八进制思考。不需要除法,移位掩码和添加/或八进制,十六进制所需的条件,将其推出 uart,或者如果您有示波器或逻辑分析仪,将其推出并行或其他串行接口(比 uart 速度快得多)。
【解决方案2】:
  1. 可能是您的优化器注意到value 是一个自动变量,其地址从未被占用,因此实际上忽略了它的易失性这一事实,因为它碰巧知道一些关于它运行的架构的信息,并得出结论,即使标准说这是可观察的,符合标准的程序也无法观察到它发生的读取和写入顺序。显然这对调试器不是很友好,但如果它发生了,我也不会感到惊讶。实际上,编译器会假设您无法“看到”堆栈,如果您使用调试器,检查核心转储,将堆栈标记为只读并处理结果信号等,这是错误的。检查反汇编,看看 multipy/shift 和 bit-set 是否真的出现了。
  2. 可能是因为 (1) 或其他原因,您的调试器没有正确跟踪该值。

【讨论】:

  • 0xA0000000 在我正在开发的电路板的内存映射中具有重要意义。
  • 它实际上并不是未定义的,否则嵌入式系统永远无法声称符合内存映射 I/O。标准规定,仅当“已为指针分配了无效值”时,它才是未定义的——无效值包括 null、错误对齐和对象在其生命周期之后,但这就是它要说的全部内容。 0xa0000000是否无效是实现的问题。
  • @pax:当然,这实际上是SHRT_MAX + 1 之类的情况之一,无论是否定义行为都是由实现定义的。因此,在此处尚未命名的特定 C 实现中,恰好是 Randomblue 正在使用的,它已定义:-)
【解决方案3】:

尝试将值写入另一个临时变量并检查该值。有时这会欺骗编译器/调试器做你想做的事。 AFAIK,volatile 告诉编译器始终读取该值,如果它从未读取过,则不一定要保留它以进行写入。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-07-27
    • 1970-01-01
    • 1970-01-01
    • 2021-05-28
    • 1970-01-01
    • 1970-01-01
    • 2021-03-07
    • 2014-11-25
    相关资源
    最近更新 更多