在 C 和 C++ 中,使用逗号运算符的表达式是否未定义"a = b, ++a;"?
In C and C++, is an expression using the comma operator like "a = b, ++a;" undefined?
取以下三个C代码片段:
1) a = b + a++
2) a = b + a; a++
3) a = b + a, a++
每个人都知道示例 1 是一件非常糟糕的事情,并且显然调用了未定义的行为。示例 2 没有问题。我的问题是关于示例 3。逗号运算符在这种表达式中是否像分号一样工作?2 和 3 是等价的还是 3 和 1 一样未定义?
具体来说,我正在考虑关于类似free(foo), foo = bar
的事情.这基本上与上述问题相同。我能否确定foo
在重新分配之前已释放,或者这是一个明确的序列点问题?
我知道这两个例子在很大程度上都是毫无意义的,只使用分号并完成它更有意义。我只是出于好奇而问。
情况 3 定义良好。
首先,让我们看看表达式是如何解析的:
a = b + a, a++
逗号运算符,
的优先级最低,其次是赋值运算符=
、加法运算符+
和后缀运算符++
。 因此,使用隐式括号将其解析为:
(a = (b + a)), (a++)
从这里开始,C 标准中关于逗号运算符,
的第 6.5.17 节如下:
2逗号运算符的左操作数被计算为空表达式;其之间有一个序列点 评估和正确操作数的评估。然后右边 计算操作数;结果有其类型和值
C++11 标准的第 5.14 p1 节具有类似的语言:
用逗号分隔的一对表达式从左到右计算; 左侧表达式是丢弃值表达式。与左边相关的每个值计算和副作用 表达式在每个值计算和副作用之前排序 与正确的表达相关联。结果的类型和值 是正确操作数的类型和值;结果是一样的 值类别作为其右操作数,如果其右操作数,则为位字段 操作数是一个 glvalue 和一个位字段。
由于序列点,a = b + a
保证在表达式a = b + a, a++
a++
之前完全计算。
关于free(foo), foo = bar
,这也保证了foo
在分配新值之前是自由的。
a = b + a, a++;
是明确定义的,但a = (b + a, a++);
可以是未定义的。
首先,运算符优先级使表达式等价于(a = (b+a)), a++;
,其中+
具有最高优先级,其次是=
,后跟,
。逗号运算符在其左操作数和右操作数的计算之间包含一个序列点。所以代码无趣地完全等同于:
a = b + a;
a++;
这当然是明确定义的。
如果我们改写a = (b + a, a++);
,那么逗号运算符中的序列点将无法挽救这一天。因为那时表达式将等效于
(void)(b + a);
a = a++;
- 在C和C++14或更早版本中,
a = a++
是未排序的(见C11 6.5.16/3(。这意味着这是未定义的行为(根据 C11 6.5/2(。请注意,C++11 和 C++14 的表述不当且模棱两可。 - 在 C++17 或更高版本中,
=
运算符的操作数从右到左排序,这仍然是明确定义的。
所有这些都假设没有发生C++运算符重载。在这种情况下,将评估重载运算符函数的参数,在调用函数之前发生一个序列点,从那里发生的情况取决于该函数的内部结构。
- 不知道某个东西是否被忽略会引入未定义的行为吗
- 此增量后语句是否会导致未定义的行为?
- Windows 链接器是否使用 LoadLibrary 解析 DLL 中未定义的符号?
- 如何测试 size_t -1 是否未定义,其中 size_t 为 0?
- 在销毁期间从另一个线程调用对象上调用方法是否未定义行为?
- 从 std::string 到 std::array<char,size> 的 memcopy 额外数据是否是一种未定义的行为?
- 负指数是否必然意味着未定义的行为
- 在"printf"中使用标签"h"或"hh"是否涉及未定义的
- 在 C++17 中,是否未定义使用无锁原子学保护从信号处理程序传递的数据?
- C++ 如何检查 char 变量是否未定义(未初始化)
- 递减 std::vector::begin 是否未定义,即使它从未被使用过?
- 访问从联合与另一个成员集复制的联合中的一个成员是否未定义或未指定?
- 在C++中,转换为simd类型是否有未定义的行为
- 是否是从等待返回到悬而未决的"this"实例的未定义行为?
- 是否未定义将对函数范围变量的引用作为值返回
- FBString 的小字符串优化是否依赖于未定义的行为?
- 移动 std::bitset<N> 是否超过 N 个位置未定义的行为?
- 创建指针是否超过非数组指针的末尾,而不是从 C++17 中的一元运算符和未定义的行为派生?
- 使用c_str是否有未定义的异常行为
- i=i++;未定义.是否i=foo(i++)也未定义