RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 754881
Accepted
wololo
wololo
Asked:2020-12-07 04:19:01 +0000 UTC2020-12-07 04:19:01 +0000 UTC 2020-12-07 04:19:01 +0000 UTC

C++中的赋值运算符

  • 772

语言标准中对赋值运算符的描述有几点我不清楚,我想澄清一下。

n4659,8.18/1:

[...] 在所有情况下,赋值都在左右操作数的值计算之后和赋值表达式的值计算之前进行排序。右操作数在左操作数之前排序。对于不确定顺序的函数调用,复合赋值的操作是单次求值。[注意:因此,函数调用不应干预左值到右值的转换以及与任何单个复合赋值运算符相关的副作用。——尾注]

问题 1. 什么是值计算,它是按照以下代码中左右操作数的标准执行的:

a = 1;

问题 2. 函数调用的不确定顺序是什么意思?我想看一个在同一个表达式中涉及赋值和函数调用的示例,其中函数调用相对于某物是无限排序的。

n4659, 8.18/8:

如果存储在一个对象中的值是通过另一个对象读取的,该对象以任何方式与第一个对象的存储重叠,那么重叠应该是精确的,并且两个对象应该具有相同的类型,否则行为是未定义的。[注:此限制适用于赋值操作的左右关系;它不是关于分配的目标通常如何别名的声明。见 6.10。——尾注]

问题 3. 我想看一个符合上述引用描述的例子。


除了问题 1。

也许将问题如下提出更有意义:从语言标准的角度来看,值计算是否总是在赋值运算符的操作数上执行?如果没有,什么时候完成,什么时候没有?

重点是这个。这个问题的第一句话说赋值发生在两个操作数的值计算发生之后。它还说右操作数在左操作数之前排序(即,与右操作数相关的值计算 + 副作用将发生在与左操作数相关的值计算 + 副作用之前)。

因此,如果在赋值运算符中,左操作数的值计算总是发生在实际赋值之前,那么右操作数总是在赋值之前排序。

c++
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. Best Answer
    ixSci
    2020-12-07T13:34:34Z2020-12-07T13:34:34Z

    “值计算”是计算表达式值的过程,即 得到它的结果。例如,假设我们有int i = 0,那么计算的表达式i++将返回0。这里重要的是它i++包含副作用。因此,在计算了上述表达式后,我们不保证所需的更改(增量)同时应用于它。为什么这很重要?让我们以这个标准长达 17 年。其中,表达式:i = i++具有未定义的行为,因为i相对于赋值,for 的增量没有以任何方式排序:它可以发生在之前或之后。

    另一方面,如果我们采用一个表达式++i,那么在计算表达式之前会在其中应用副作用,这使得这样的表达式i = ++i有效并且不包含未定义的行为。


    现在到第二个问题。假设我们有一个全局变量:long long global = 0;和一个函数auto foo() {return global += 1;}。例如,我们还需要这样的函数void ignore(long long, long long)和 C++17(仅是为了保证函数参数的不确定顺序评估)。

    最后,考虑下面的代码:ignore(global += BIG_NUMBER, foo()),所以,理论上,如果你删除这个规则,那么可能会导致以下情况(在某些平台上记录long long将在几个指令中):我们开始从global外部写入我们的,我们写向下一部分,但这里有一个代码切换foo(根据编译器的决定)并重写我们写下的内容。之后,我们继续记录,我们的变量global包含垃圾。那些。该规则禁止交错(interleaving,overlapping)表达式的求值,编译器无权做我在上句中描述的事情。

    但这都是理论,因为标准明确禁止 (C++14[intro.object]p13) 交错所有表达式,除了未排序的表达式,所以这样的澄清对我来说似乎是多余的。


    第三个引用禁止这样做:

    int i = 0;
    char* ptr = reinterpret_cast<char*>(&i);
    // Вот тут проблема
    *ptr = static_cast<char>(i);
    

    那些。左边和右边不应该有两个对象指向同一个内存区域,但具有不同的类型。


    关于添加:这里值得引用 C++17[intro.object]p15:

    <...> 如果与表达式 X 关联的每个值计算和每个副作用都在每个值计算和与表达式 Y 关联的每个副作用之前排序,则表示表达式 X 在表达式 Y 之前排序

    这样就足够了。根据 C++17 中引入的规则,赋值表达式的右侧排序在前(sequenced before):

    右操作数在左操作数之前排序

    这是理解的关键:在我们分配一个新值之前,或者甚至开始计算我们在那里分配的内容之前,右边的一切都必须解决。此规则使代码i = i++正确,尽管在 C++17 之前这是未定义的行为。

    • 3
  2. αλεχολυτ
    2020-12-07T13:26:47Z2020-12-07T13:26:47Z

    在赋值运算符的左侧和右侧,都可以有比您的示例中指示的更复杂的实体。例如,左边可能有一个返回引用的函数,右边可能有一个返回值的函数。在这里,调用这些函数来获取左右部分的值就是值计算。对于您的情况,我们可以说变量的地址是在左侧计算的a,而文字的值是在右侧计算的1。

    关于“不确定顺序的函数调用”的短语表示复合运算符,例如+=,*=等。当用作函数参数时,应将其视为单个(不可分割的)评估。例如,当调用以下函数时:

    f (a() += b(), c())
    

    在对 和的调用c()之间不能发生调用。a()b()

    对于第三个问题 - 假设您有一个字节数组。你有两个指针,比字节重,指向该数组中的数据。同时,解引用这些指针会用到原始数组的一些公共部分,即会有一个交集。这些是取消引用的指针,不能在赋值中使用。

    • 2

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    Python 3.6 - 安装 MySQL (Windows)

    • 1 个回答
  • Marko Smith

    C++ 编写程序“计算单个岛屿”。填充一个二维数组 12x12 0 和 1

    • 2 个回答
  • Marko Smith

    返回指针的函数

    • 1 个回答
  • Marko Smith

    我使用 django 管理面板添加图像,但它没有显示

    • 1 个回答
  • Marko Smith

    这些条目是什么意思,它们的完整等效项是什么样的

    • 2 个回答
  • Marko Smith

    浏览器仍然缓存文件数据

    • 1 个回答
  • Marko Smith

    在 Excel VBA 中激活工作表的问题

    • 3 个回答
  • Marko Smith

    为什么内置类型中包含复数而小数不包含?

    • 2 个回答
  • Marko Smith

    获得唯一途径

    • 3 个回答
  • Marko Smith

    告诉我一个像幻灯片一样创建滚动的库

    • 1 个回答
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Алексей Шиманский 如何以及通过什么方式来查找 Javascript 代码中的错误? 2020-08-03 00:21:37 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5