考虑以下陈述
volatile int a = 7;
a; // statement A
volatile int* b = &a;
*b; // statement B
volatile int& c = a;
c; // statement C
现在,我一直在试图在标准中找到一点,告诉我当遇到这些语句时编译器是如何工作的。我所能找到的只是A(可能还有C)给了我一个左值,B也一样:
标识符是一个id表达式,前提是它已被适当声明(第7条)。[..]
[…]结果是由标识符表示的实体。如果实体是函数、变量或数据成员,则结果为左值,否则为prvalue
[…]
一元*运算符执行间接寻址:应用它的表达式应是指向对象类型的指针,或指向函数类型的指针,结果是一个左值,表示表达式指向的对象或函数。
我在clang 3.2-11和g 4.7.3中尝试了这个,第一个在C 11模式下产生了三次读取,在C 03模式下产生了零读取(输出三个警告),而g只产生了前两个,明确警告我第三个不会产生。
很明显,哪种类型的值来自表达式,来自标准中引用的行,但是:
根据C标准,哪种语句(A、B、C)应该从易失性实体产生读取?
这是gcc文件7.1,何时访问易失性C对象?在这里是相关的,我引述(我接下来的重点):
C标准与C标准在处理挥发性物体方面有所不同。它没有具体说明什么构成挥发性访问,只是说C在挥发性方面的行为应该与C类似
在空上下文中访问对象时,C和C语言规范不同:
并提供了这个例子:
volatile int *src = somevalue;
*src;
接着说:
C标准指定此类表达式不进行左值到右值的转换,并且取消引用的对象的类型可能不完整。C标准没有明确指定导致访问的是左值到右值的转换。
应参考标准草案第5.3.1节一元运算符第1段,其中规定:
一元*运算符执行间接寻址:应用它的表达式应是指向对象类型的指针,或指向函数类型的指针,结果是一个左值,表示表达式指向的对象或函数。[...]
关于参考文献:
当使用对volatile的引用时,G不会将等效表达式视为对volatile的访问,而是发出警告,表示没有访问volatile。这样做的理由是,否则就很难确定易失性访问发生在哪里,也不可能忽略返回易失性引用的函数的返回值。同样,如果希望强制读取,请将引用转换为右值。
因此,gcc
似乎选择以不同的方式处理对volatile的引用,为了强制读取,您需要强制转换为右值,例如:
static_cast<volatile int>( c ) ;
它从第5.2.9节
Static cast生成一个prvalue,并由此进行左值到右值的转换:
表达式static_cast(v)的结果是将表达式v转换为类型T的结果。如果T是左值引用类型或函数类型的右值引用,则结果为左值;如果T是对象类型的右值引用,则结果为xvalue;否则,结果为prvalue。
更新
C 11标准草案增加了5
表达式第11段,其中规定:
在某些情况下,表达式只会因其副作用而出现。这样的表达式称为废弃值表达式。表达式将被求值,其值将被丢弃。数组到指针(4.2)和函数到指针(4.3)的标准转换不适用。当且仅当表达式是volatile限定类型的左值且为下列之一时,才会应用左值到右值的转换(4.1):
并包括:
-id表达式(5.1.1),
这对我来说似乎是模棱两可的,因为关于a;
和c;
部分5.1.1 p8
说它是一个左值
,它对我来说并不明显,它涵盖了这种情况,但乔纳森发现DR 1054说它确实涵盖了这种情况。
关于“隐式取消引用”的G警告来自gcc/cp/cvt. c
中的代码,该代码故意不通过引用加载值:
/* Don't load the value if this is an implicit dereference, or if
the type needs to be handled by ctors/dtors. */
else if (is_volatile && is_reference)
G故意这么做,因为如手册所述(何时访问易失性C对象?)该标准不清楚什么构成对易失性限定对象的访问。如上所述,您需要强制进行左值到右值的转换,以强制从volatile加载。
Clang在C 03模式下发出警告,表示类似的解释:
a.cc:4:3: warning: expression result unused; assign into a variable to force a volatile load [-Wunused-volatile-lvalue]
a; // statement A
^
a.cc:6:3: warning: expression result unused; assign into a variable to force a volatile load [-Wunused-volatile-lvalue]
*b; // statement B
^~
a.cc:8:3: warning: expression result unused; assign into a variable to force a volatile load [-Wunused-volatile-lvalue]
c; // statement C
^
3 warnings generated.
对于C 03,G行为和GCC手册似乎是正确的,但C 11与C 03之间存在差异,这是由DR 1054介绍的(这也解释了为什么在C)3和C 11模式下,Clang的行为不同)。5[expr]p10定义了一个废弃的值表达式,并表示对于volatile,左值到右值的转换应用于id表达式,例如语句a和C。左值到右值的转换规范(4.1[conv.lval])表示结果是glvalue的值,它构成了volatile的访问。根据5p10,所有三条语句都应该是access,因此G对语句C的处理需要更新以符合C 11。我把它报告为http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59314
根据JLS 17规范第17.3节: 例如,在下面的(断开的)代码片段中,假设这是。“完成”是一个非易失性布尔字段: 编译器可以自由读取此字段。只执行一次,并在每次执行循环时重用缓存的值。这意味着循环永远不会终止,即使另一个线程更改了这个值。完成 我尝试模拟以下示例:两个线程同时访问同一个布尔变量,第一个线程使用while循环中的共享布尔值,第二个线程更新布尔值。 1、代码无线程。第一个线程内的sl
问题内容: 我想删除以AAA开头的Jenkins作业列表(例如) 当我用显式字符串做它很好用 但是,当我尝试从Jenkins Build属性获取正则表达式时,我失败了,并且if没有被调用… 运行它时,我会得到所有作业的列表:在工作区中构建/ var / lib / jenkins / jobs / Bulk_Delete_Job / workspace 但是什么也不会被删除/不会打印“ TEST”
编程语言最强大的功能就是操作变量。变量就是一个有值的代号。 2.1 赋值语句 赋值语句的作用是创建一个新的变量,并且赋值给这个变量: >>> message = 'And now for something completely different'>>> n = 17 >>> pi = 3.141592653589793 上面就是三个赋值语句的例子。第一个是把一个字符串复制给名叫message的
我正在对科特林进行修补,我正试图让我的头脑了解科特林中可为空的变量是如何工作的。这里我有一段代码,它执行布尔检查,以查看车辆是否超载。实现是处理可空变量的好方法还是有更优雅的方法? 非常谢谢!
我正在用php和ajax创建一个消息传递站点。 获取对话有问题。 问题是,每当两个用户在他们之间聊天时,就会有两个id不同的行; A和B正在聊天,彼此只写了4条消息 消息数据库是这样的 我的目标是用这个代码获取记录 $页面所有者是登录的用户; 使用这种方法,我可以进行两次相同的对话 a 代码在页面上给了我两次对话,我只想得到一个结果; 我的整个php代码是这样的
编程语言最强大的特性之一,是操作变量的能力。变量是指向某个值的名称。 赋值语句 赋值语句(assignment statement)会新建变量,并为这个变量赋值。 >>> message = 'And now for something completely different' >>> n = 17 >>> pi = 3.141592653589793 这个例子进行了三次赋值。 第一次将一个字