括号是否强制执行评估顺序并定义未定义的表达式?

Dol*_*hay 13 c c++ expression operator-precedence undefined-behavior

当我遇到这个问题时,我正在阅读我的教科书

  1. 在下面的表达式之后,a的值是多少?
    假设a的初始值为5.Mention步骤
    • 一个+ =(A ++)+(++ A)

起初我认为这是未定义的行为,因为a已被多次修改.
那么我就读了这个问题并说它提到了步骤所以我可能认为这个问题是正确的.

所以我的问题是:

  • 应用括号是否定义了未定义的行为?
  • 是否在评估括号表达式后创建了序列点?
  • 如果已定义,则括号如何重要,因为++和()具有相同的优先级

注意:一个解释清楚的答案将得到我的投票

aja*_*jay 13

不,应用括号不会使其成为定义的行为.它仍然未定义.C99标准§6.52说

在前一个和下一个序列点之间,对象的存储值最多只能通过表达式的计算来修改一次.此外,先前的值应该只读以确定要存储的值.

在括号中放置子表达式可能会强制子表达式的求值顺序,但它不会创建序列点.因此,它不保证何时会发生子表达式的副作用,如果它们产生任何副作用.再次引用C99标准§5.1.2.32

表达的评估可能产生副作用.在称为序列点的执行序列中的某些特定点处,先前评估的所有副作用应该是完整的,并且不会发生后续评估的副作用.

为了完整起见,以下是附件C中C99标准规定的序列点.

  1. 在评估参数之后调用函数.

  2. 以下运算符的第一个操作数的结尾:logical AND && ; 逻辑OR || ; 条件; 逗号,.

  3. 完整声明者的结尾.

  4. 完整表达的结束; 表达式中的表达式; 选择语句的控制表达式(ifswitch); whiledo 语句的控制表达式; for语句的每个表达式; 返回语句中的表达式.

  5. 在库函数返回之前.

  6. 在与每个格式化的输入/输出函数转换说明符相关联的操作之后.

  7. 紧接在每次调用比较函数之前和之后,以及对比较函数的任何调用和作为参数传递给该调用的对象的任何移动之间.

  • 说这是由一个不知道他们在谈论什么的人写的. (9认同)
  • @AkshayLAradhya:我建议使用批判性判断.1.并非所有写的都是真实的(x-ref帮助,但不能证明任何东西)和2.任何公司的目标首先是赚钱(而且准确是昂贵的,可能没什么好处) (4认同)

Sha*_*our 5

加括号不会创建一个序列点,并在更现代的标准就不会创建测序之前对于关系到副作用,这是与你有,除非指出,这其余的将相对于C中的表达问题+ +11.括号是主要表达式中涵盖的5.1 主要表达式,它具有以下语法(强调我的前进):

primary-expression:
  literal
  this
  ( expression )
  [...]
Run Code Online (Sandbox Code Playgroud)

并在第6段中说:

带括号的表达式是一个主表达式,其类型和值与所包含表达式的类型和值相同.括号的存在不会影响表达式是否为左值.除非另有说明,否则带括号的表达式可以在可以使用所包含的表达式的上下文完全相同的上下文中使用,并且具有相同的含义.

postfix ++是有问题的,因为我们无法确定何时更新的副作用a将在C++ 11之前发生,而在C中这适用于postfix ++prefix ++操作.关于prefix ++在C++ 11中如何更改未定义的行为,请参阅C11表达式中的赋值运算符排序.

+=操作有问题,因为:

[...] E1 op = E2相当于E1 = E1 op E2,但E1只评估一次 [...]

所以在C++ 11中,以下是从undefined到定义的:

a = ++a + 1 ;
Run Code Online (Sandbox Code Playgroud)

但这仍未定义:

a = a++ + 1 ;
Run Code Online (Sandbox Code Playgroud)

以上两者都是在C++ 11和C99和C11之间未定义的.

从草案C++ 11标准部分开始,1.9 程序执行15段说:

除非另有说明,否则对单个运算符的操作数和单个表达式的子表达式的评估是不确定的.[注意:在程序执行期间不止一次评估的表达式中,不需要在不同的评估中一致地执行对其子表达式的未序列和不确定顺序的评估.-end note]运算符操作数的值计算在运算符结果的值计算之前排序.如果对标量对象的副作用相对于同一标量对象的另一个副作用或使用相同标量对象的值进行的值计算未被排序,则行为未定义.

  • @AkshayLAradhya看到我的更新,它无效`postfix ++`和`+ =`创建未定义的行为. (2认同)