【发布时间】:2019-01-07 09:09:48
【问题描述】:
给定以下代码:
unsigned int global_flag = 0;
void exception_handle()
{
global_flag = 1;
}
void func()
{
/* access will cause exception which will assign global_flag = 1
then execution continues */
volatile unsigned int x = *(unsigned int *)(0x60000000U); /* memory protection unit configured to raise exception upon accessing this address */
if (global_flag == 1)
{
/* some code */
}
}
鉴于volatilemust not be reordered across sequence points:
最低要求是在一个序列点之前的所有 对 volatile 对象的访问已经稳定,并且没有后续 已发生访问
并给出以下关于sequence points:
序列点出现在以下位置... (1) .. (2) .. (3) 在完整表达式的末尾。此类别包括表达式 语句(例如赋值 a=b;)、return 语句、 if、switch、while 或 do-while 语句的控制表达式, 以及 for 语句中的所有三个表达式。
是否承诺volatile unsigned int x = *(unsigned int *)(0x60000000U); 会在if (global_flag == 1) 之前发生(在二进制asm 中,CPU 乱序执行与这里无关)?
根据上面的引用,volatile unsigned int x = *(unsigned int *)(0x60000000U); 必须在下一个序列点结束之前被评估,而volatile unsigned int x = *(unsigned int *)(0x60000000U); 本身就是一个序列点,所以这意味着每个volatile 分配都在分配时被评估?
如果上述问题的答案是否定的,那么下一个序列点在if的end,是否意味着可以执行类似的操作:
if (global_flag == 1)
{
volatile unsigned int x = *(unsigned int *)(0x60000000U);
/* some code */
}
系统是一个嵌入式的-ARM cortex m0,单核,单线程应用程序。
【问题讨论】:
-
如果我理解正确,那么第一个问题是“是”?为什么你认为它可能是“不”?当然,如果编译器可以知道您的代码必须导致未定义的行为,它可以假设例如代码永远不会被访问并完全优化它... 您不能依赖未定义的行为以定义的方式工作C!
-
在您的示例中,
global_flag定义中缺少volatile是错误还是有意选择? -
@hyde 当然,许多低级编程环境都支持代码模式,这些代码模式通常以定义和确定的方式未定义的行为。
-
这里有一个有趣而微妙的点:您的代码不包含赋值,只是一个初始化,我相信在带有初始化器的定义的末尾没有序列点。我也认为这是标准中的一个缺陷。
-
ILLEGAL_ADDRESS是什么?
标签: c language-lawyer volatile