挥发性和序列点

时间:2019-01-07 09:09:49

标签: c language-lawyer volatile

给出以下代码:

oc tag docker-registory.svc:5000/myproject/myapp@sha256:231d3371ad687233f7a6140c67a314c416105b424c19f28b124ca298989998b3 myproject/myapp:test

Tag myapp:test set to docker-registory.svc:5000/myproject/myapp@sha256:231d3371ad687233f7a6140c67a314c416105b424c19f28b124ca298989998b3.

root@018fdb569d8a:/# oc get is
NAME DOCKER REPO TAGS UPDATED
myapp docker-registory.svc:5000/myproject/myapp latest,test 5 minutes ago

root@018fdb569d8a:/# oc describe is
Name: myapp
Namespace: myproject
Created: 7 minutes ago
Labels: app=myapp
Description: Keeps track of changes in the application image
Annotations: openshift.io/generated-by=OpenShiftNewApp
openshift.io/image.dockerRepositoryCheck=2019-01-07T03:44:42Z
Docker Pull Spec: docker-registory.svc:5000/myproject/myapp
Image Lookup: local=false
Unique Images: 1
Tags: 2

latest
no spec tag

docker-registory.svc:5000/myproject/myapp@sha256:231d3371ad687233f7a6140c67a314c416105b424c19f28b124ca298989998b3
5 minutes ago
test
tagged from docker-registory.svc:5000/myproject/myapp@sha256:231d3371ad687233f7a6140c67a314c416105b424c19f28b124ca298989998b3

! error: Import failed (InternalError): Internal error occurred: Get https://docker-registory.svc:5000/v2/: x509: certificate signed by unknown authority

鉴于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 */ } } must not be reordered across sequence points

  

最低要求是所有先前的序列点   对易失性对象的访问已稳定,此后没有任何访问   发生访问

给出有关sequence points的以下信息:

  

序列点出现在以下位置...(1)..(2)..(3)完整表达式的结尾。此类别包括表达   语句(例如赋值 a = b ;),返回语句,   控制 if 的表达式,switch,while或do-while语句,   以及for语句中的所有三个表达式。

是否已承诺volatile将在volatile unsigned int x = *(unsigned int *)(0x60000000U);之前发生(在二进制asm中,CPU的无序执行在这里不相关)?

根据以上引用,if (global_flag == 1)必须在下一个序列点结束之前进行评估,并且volatile unsigned int x = *(unsigned int *)(0x60000000U);本身就是一个序列点,因此这意味着每个volatile unsigned int x = *(unsigned int *)(0x60000000U);分配在分配时间进行评估?

如果以上问题的答案为否,则下一个序列点位于volatile末端,是否表示可以执行类似的操作?

if

系统是嵌入式单ARM cortex m0,单核,单线程应用程序。

2 个答案:

答案 0 :(得分:2)

  

是否已承诺volatile unsigned int x = *(unsigned int *)(ILLEGAL_ADDRESS);将在if(global_flag == 1)之前发生

来自内容丰富的C11 AnnexC(添加了换行符/格式以提高可读性):

  

以下是5.1.2.3中描述的顺序点:
  ...
  -在评估一个完整表达式和下一个要评估的完整表达式之间。
  -以下是完整的表达方式:
  -不属于复合文字(6.7.9)的初始化程序;
  -表达式语句中的表达式(6.8.3);
  -选择语句(if或switch)的控制表达式(6.8.4);
  -while或do语句的控制表达式(6.8.5);
  -for语句(6.8.5.3)的每个(可选)表达式;
  -return语句(6.8.6.4)中的(可选)表达式。

由于*(unsigned int *)(ILLEGAL_ADDRESS);是一个初始化程序(赋值表达式),并且该初始化程序不是复合文字的一部分,因此它是一个完整表达式。下一个完整表达式是if中的控制语句,因此在ifx的初始化之间有一个序列点。

来自著名的C11 5.1.2.3p6

  

符合标准的实现的最低要求是:

     

严格根据抽象机的规则评估对易失对象的访问。
  ...

由于x是一个易失对象,因此严格地将其初始化为抽象机,因此在序列点之后,它的右值必须等于*(unsigned int *)(ILLEGAL_ADDRESS)操作的结果。

是的,x对象的初始化必须在if内部的控件表达式之前进行。

关于未定义的行为,引自C11 6.5.3.2p4

  

如果已将无效值分配给指针,则一元*运算符的行为是不确定的。

您评论过:

  

我的系统内存模型中不允许访问地址0x60000000

可以推断出(unsigned int*)0x60000000是无效的指针,因此一元*运算符应该spawn dragons

答案 1 :(得分:2)

在您的代码段中,变量global_flag不易失,因此没有什么可以阻止编译器跨序列点移动对global_flag的访问,或者在环境允许的情况下完全删除它。谈论访问x和访问global_flag的顺序是没有意义的,因为后者不是一个可观察到的事件,只有前者是可见的。

(还请注意,表达式volatile中没有*(unsigned int *)(0x60000000U)限定符。我认为确实是您要特别对待的表达式,但是您的代码却没有这样做。编译器是允许产生事先对*(unsigned int *)(0x60000000U)进行评估的代码,然后在其板上进行大量其他处理,然后将获得的值分配给x,这将满足C的约束标准放在volatile左值上。)

如果您的代码段中包含unsigned int volatile global_flag = 0;*(volatile unsigned int *)(0x60000000U),那么“是否答应……”这个问题的答案将是明确的“是”。