【问题标题】:Embedded C: Able to access some struct members but not others嵌入式 C:能够访问某些结构成员但不能访问其他成员
【发布时间】:2015-07-28 03:05:07
【问题描述】:

问题

在我的个人项目中,我在 UART 抽象库中定义了一个结构(我们称之为 UART.c 和 UART.h),我为 AVR 制作。

在 UART.h 中:

typedef struct ST_UARTRX_MESSAGECONTENTS{
 uint8_t u_command[3];          //Command 
 uint32_t u32_value;            //Parameter for Command
 boolean b_newValue;    //Is there new value written here
 boolean b_Error;       //Is there an error with this message
} ST_UARTRX_MESSAGECONTENTS;

volatile ST_UARTRX_MESSAGECONTENTS st_uartRX_MessageContents;

所以基本上它是一个保存 UART 消息的结构,它有一个“b_newValue”,它是接收新消息时的标志。当 AVR 接收到一个新行“\n”时,一条消息被“接收”。

在另一个文件的头文件中(我们称之为“foo.h”):我包含我的“UART抽象库”并将其放在头文件中:

extern volatile ST_UARTRX_MESSAGECONTENTS st_uartRX_MessageContents;

然后在 foo.c 中,我尝试访问“b_newValue”:

if(st_uartRX_MessageContents.b_newValue){
    st_uartRX_MessageContents.b_newValue = TRUE;  
    fsm_state = ST_STOREMACRO;
}

但是即使我的调试器说结构值确实是真的,也永远不会输入“if”:

你可以看到我已经打破了 if 语句。如果我点击“Step”,它只是跳过它并且不进入!

Boolean typedef 供参考:

typedef enum{FALSE, TRUE} boolean;

我尝试过的一些事情

当我查看已编译的 ASM 代码时,我看到通用寄存器 R24 用于加载 b_newValue,但它加载的是 0x00,而不是我期望的 0x01。

uartTX_sendArray(st_uartRX_MessageContents.u_command, sizeof st_uartRX_MessageContents.u_command);
delay_ms(2000);
if(st_uartRX_MessageContents.b_newValue){
    st_uartRX_MessageContents.b_newValue = TRUE;  
    fsm_state = ST_STOREMACRO;
}

我使用我的“UART:发送此数组”函数从相同的结构发送 ascii“命令”,它可以工作!我不知道为什么我的 foo.c 可以看到“命令”而不是“b_newValue”。

我已经把头发扯了好几个小时了。感谢观看。

【问题讨论】:

  • 从您发布的代码的布局来看,typedef struct ST_UARTRX_MESSAGECONTENTS{... 位于定义volatile ST_UARTRX_MESSAGECONTENTS st_uartRX_MessageContents; 的同一文件中,该文件应该是.c 文件。但是您是如何设法在.h 文件中声明extern volatile ST_UARTRX_MESSAGECONTENTS st_uartRX_MessageContents; 的呢?在这种情况下,名称 ST_UARTRX_MESSAGECONTENTS 不应该在 .h 文件中知道。那么它是如何工作的呢?您能否提供有关声明和定义如何分布在不同源文件中的更准确信息?
  • fsm_state 的值是多少?如果它始终是ST_STOREMACRO,并且由于您将TRUE 存储到b_newValue 中,而它已经是TRUE,那么编译器是否有可能优化了整个块,因为它在逻辑上是一个 noop?
  • 我要问的原因是,如果这样的声明布局编译,那么你可能在其他地方有另一个独立声明ST_UARTRX_MESSAGECONTENTS不同的成员序列。这样的事情很容易混淆调试器并导致您观察到的效果。
  • b_newValue 被加载到 ASM 中的寄存器而不是总是从主内存中读取时,这里肯定发生了一些奇怪的事情,这表明对结构成员的访问不是实际上易变。如果所有其他方法都失败了,您可能可以通过执行以下操作来强制读取:*(volatile boolean *) &st_uartRX_MessageContents.b_newValue 这显然很可怕,但只能作为最后的手段使用。
  • @AnT 感谢您的意见。 typedef 在 UART 抽象的头文件中。 extern 结构位于 foo.h 中,其中包含 UART 抽象库的标头。我将尝试在上面澄清这一点。

标签: c struct boolean avr


【解决方案1】:

从你现在发布的内容来看,你的结构对象定义在头文件UART.h

volatile ST_UARTRX_MESSAGECONTENTS st_uartRX_MessageContents;

这在形式上是非法的(如果您将 UART.h 包含到多个翻译单元中)并且即使某些编译器接受它作为扩展名通常也不是一个好主意。我建议您将上述定义移动到 UART.c 文件中并放置一个非定义声明

extern volatile ST_UARTRX_MESSAGECONTENTS st_uartRX_MessageContents;

转入UART.h

【讨论】:

  • 嗨,非常感谢您抽出宝贵时间。我将 extern 添加到头文件中的定义中,并将定义放在 UART.c 的顶部。但是,即使“b_newValue”肯定设置为 TRUE,我仍然无法输入“if”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-07
相关资源
最近更新 更多