标签: sequence-points

c 中运算符与“后缀递减”和“逻辑与”运算符的关联性

免责声明:我不这样编码,我只是想了解c语言是如何工作的!!!!

输出是12。

该表达式(a-- == 10 && a-- == 9)从左到右计算,a 仍然是 10,a-- == 10但 a 是 9 a-- == 9

1)增量后评估的时间是否有明确的规则?从这个例子来看,它似乎在 && 之前但在 == 之后进行评估。是不是因为&&逻辑运算符构成了a-- == 10一个完整的表达式,所以a执行完后就更新了?

2)同样对于c / c ++,某些运算符(例如前缀递减)从右到左发生,因此a == --a首先将a递减到9,然后比较9 == 9。c / c ++这样设计有原因吗?我知道对于 Java,情况正好相反(它从左到右计算)。

#include <stdio.h>

int main() {
    int a = 10;
    if (a-- == 10 && a-- == 9)
        printf("1");
    a = 10;
    if (a == --a)
        printf("2");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

c side-effects operator-precedence sequence-points post-increment

5
推荐指数
1
解决办法
662
查看次数

写入新值是否构成预增量表达式“值计算”的一部分,还是“副作用”?

考虑以下表达式(带有说明声明):

int n = 42;
--n &= 0x01;
Run Code Online (Sandbox Code Playgroud)

这是否违反排序规则?

在我看来,预自增是左操作数“值计算”的一部分。如果这是真的,那么从 C++11 开始,这里就不存在 UB(并且从 C++17 开始,值计算副作用都是相对于赋值进行排序的)。

如果它是后置增量,那么 的修改n将仅仅是一个副作用,并且我们不会有良好的排序(直到 C++17)。

c++ sequence-points language-lawyer c++11 c++17

5
推荐指数
1
解决办法
158
查看次数

C11原子与序列点的关系

我基本上有以下代码片段:

size_t counter = atomic_fetch_sub_explicit(&atomicCounter, 1, memory_order_release);
if (counter - 1 == 0
    && atomic_load_explicit(&anotherAtomicCounter, 1, memory_order_relaxed) == 0 {
      //Some code
}
Run Code Online (Sandbox Code Playgroud)

为了正确性,重要的是 的原子加载anotherAtomicCounter发生在 的 fetch-and-sub (FAS) 之后atomicCounter。对于给定的内存顺序,通常无法保证这一点,并且加载可能会在 FAS 之前发生。但是,我想知道序列点如何影响这个特定的代码。标准中提到

如果评估 A 在评估 B 之前排序,则 A 评估将在 B 评估开始之前完成。

与规则 2 结合

在以下二元运算符的第一个(左)操作数评估之后和第二个(右)操作数评估之前有一个序列点:&&(逻辑与)、|| (逻辑或),和,(逗号)。

这意味着原子加载必须在比较之后发生,但只有在知道 FAS 的结果后才能完成比较。

我的问题是这些规则是否保证原子加载始终发生在 FAS 之后,即使使用更宽松的内存顺序也是如此?

提前致谢!

c atomic sequence-points language-lawyer stdatomic

5
推荐指数
1
解决办法
162
查看次数

我在这里正确解释了 C 的操作顺序吗?

我对CPPReference说 postincrement\xe2\x80\x99s 值评估在其副作用之前排序这一事实感到困惑,但 preincrement 没有这样的保证。

\n

我现在想出了一个例子,这很重要,但我不确定我的分析是否正确。

\n

据我了解,这两个程序的不同之处在于第一个包含 UB,而第二个则不包含:

\n
#include <stddef.h>\n#include <stdio.h>\n\nint main(void) {\n    int arr[] = {0, 1, 2};\n    int i = 1;\n    int x = ++arr[arr[i]];\n}\n
Run Code Online (Sandbox Code Playgroud)\n
#include <stddef.h>\n#include <stdio.h>\n\nint main(void) {\n    int arr[] = {0, 1, 2};\n    int i = 1;\n    int x = arr[arr[i]]++;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我对这个表达式的分析++arr[arr[i]]如下:

\n
    \n
  1. 有以下先序关系:\n
      \n
    • 的值计算在 的i值计算之前排序arr[i]
    • \n
    • 的值计算在 的arr[i]值计算之前排序arr[arr[i]]
    • \n
    • 的值计算在 的arr[arr[i]]值计算之前排序++arr[arr[i]]
    • \n
    \n …

c sequence-points language-lawyer order-of-execution

5
推荐指数
1
解决办法
144
查看次数

由于C和C++中的序列点,您遇到了哪些问题?

以下是由于序列点规则导致未定义行为的两个常见问题:

a[i] = i++; //has a read and write between sequence points
i = i++;   //2 writes between sequence points
Run Code Online (Sandbox Code Playgroud)

您在序列点方面遇到的其他事情是什么?

当编译器无法警告我们时,很难找到这些问题.

c c++ sequence-points

4
推荐指数
2
解决办法
701
查看次数

相同的代码,C#和C++中的不同输出

C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 11;
            int b = 2;
            a -= b -= a -= b += b -= a;
            System.Console.WriteLine(a);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:27

C++:

#include "stdafx.h"
#include<iostream>

int _tmain(int argc, _TCHAR* argv[])
{
       int a = 11;
       int b = 2;
       a -= b -= a -= b += b -= a;
       std::cout<<a<<std::endl;
       return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:76

相同的代码有不同的输出,有人可以告诉为什么会这样吗?帮助赞赏!!

c# c++ sequence-points

4
推荐指数
1
解决办法
485
查看次数

在C中调用函数时的序列点和未定义/未指定的行为

我试图确定我对C中序列点的理解 - 只是想检查一下.目前,我认为(1)是未定义的,而(2)仅仅是未指定的,因为在(2)中,在评估参数gh(因此我们不在i序列点之间修改两次)之后存在序列点,但是参数的评估顺序f仍未指定.我的理解是否正确?

#include <stdio.h>

int g(int i) {
    return i;
}

int h(int i) {
    return i;
}

void f(int x, int y) {
    printf("%i", x + y);
}

int main() {
    int i = 23;
    f(++i, ++i); // (1)
    f(g(++i), h(++i)); // (2)
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编辑:

这里的关键点似乎是编译器是否可以自由地在任何一个g或者h被调用之前执行增量- 我从下面的答案中理解它是,尽管我很欣赏确认情况就是这样.

c undefined-behavior sequence-points language-lawyer unspecified-behavior

4
推荐指数
1
解决办法
541
查看次数

索引一个新的map元素并且有一些东西读取它分配给它未定义的行为,或者只是未指定?

在回答了这个问题之后,对于有问题的代码是否是未定义的行为进行了长时间的讨论.这是代码:

std::map<string, size_t> word_count;
word_count["a"] = word_count.count("a") == 0 ? 1 : 2;
Run Code Online (Sandbox Code Playgroud)

首先,至少没有具体说明这一点已经确定.结果根据首先评估分配的哪一侧而不同.在我的回答中,我跟踪了四个结果案例中的每一个,其中包括首先评估哪一方的因素以及该元素之前是否存在.

还有一个简短的表格:

(x = 0) = (x == 0) ? 1 : 2; //started as
(x = 0) = (y == "a") ? 1 : 2; //changed to
Run Code Online (Sandbox Code Playgroud)

我声称它更像是这样的:

(x = 0, x) = (x == 0) ? 1 : 2; //comma sequences x, like [] should
Run Code Online (Sandbox Code Playgroud)

最后,我找到了一个似乎对我有用的例子:

i = (++i,i++,i); //well-defined per SO:Undefined Behaviour and Sequence Points
Run Code Online (Sandbox Code Playgroud)

回到原文,我把它分解成相关的函数调用,以便更容易理解:

operator=(word_count.operator[]("a"), word_count.count("a") == 0 …
Run Code Online (Sandbox Code Playgroud)

c++ operator-precedence undefined-behavior sequence-points unspecified-behavior

4
推荐指数
1
解决办法
240
查看次数

在函数调用中,为什么逗号不是序列点?

在以下代码中

int main(){  
    int a=3;  
    printf("%d %d %d",++a,a,a++);
    return 0;
}  
Run Code Online (Sandbox Code Playgroud)

按照规定,从C99附录C:,

以下是5.1.2.3中描述的序列点:

  • 在评估参数之后调用函数(6.5.2.2).
  • 以下运算符的第一个操作数的结尾:logical AND &&(6.5.13); 逻辑OR || (6.5.14); 条件?(6.5.15); 逗号,(6.5.17)

计算函数参数的顺序是未定义的,如C标准所指定.

但是,在printf的函数调用中,我们有用逗号分隔的参数,它们被分类为序列点.那么为什么这个陈述对应于未指明的行为呢?

c undefined-behavior sequence-points

4
推荐指数
1
解决办法
137
查看次数

排序健全性检查

我的问题的上下文是一个简单的基于堆栈的虚拟机的实现.我对加法和乘法运算的实现如下所示:

    case OP_ADD: Push(Pop() + Pop()); break;
    case OP_MUL: Push(Pop() * Pop()); break;
Run Code Online (Sandbox Code Playgroud)

由于加法和乘法是可交换操作,只要第一个Pop调用(无论哪个是)的副作用(即,更新虚拟机的堆栈指针)将被完成,所以评估Pop调用的顺序并不重要.在另一个Pop电话之前.

通过减法和除法,顺序确实重要,因此我们必须确保控制首先执行哪个Pop.例如,这是减法操作的实现:

    case OP_SUB: {
        const auto subtrahend = Pop();
        const auto minuend = Pop();
        Push(minuend - subtrahend);
        break;
    }
Run Code Online (Sandbox Code Playgroud)

我听说模糊的说法C++ 17已经收紧了序列点和排序规则,但我没有听到细节.在这方面,我不再是语言律师自信地解析规范了.

C++ 17中的更改是否提供了足够的排序保证,减法可以作为单个表达式实现,如加法和乘法?Pop()调用的顺序及其副作用是定义的,实现定义的还是未指定的?

c++ sequence-points

4
推荐指数
1
解决办法
48
查看次数