首页 >后端开发 >C++ >`i = i` 是否会在 C 中调用用户定义类型的未定义行为?

`i = i` 是否会在 C 中调用用户定义类型的未定义行为?

Mary-Kate Olsen
Mary-Kate Olsen原创
2024-12-05 10:36:15817浏览

Does `i  =   i` Invoke Undefined Behavior with User-Defined Types in C  ?

重新审视未定义行为:序列点和用户定义类型

问题:

在上一篇关于未定义行为和序列点的文章中,表达式 i = i 被认为是调用内置类型的未定义行为。然而,问题来了:如果 i 的类型是用户定义的怎么办?具体来说,假设我们有一个带有重载运算符的 Index 类。

答案:未定义的行为与明确定义的行为

与直觉相反,事实证明,表达式 i = i 不会调用 Index 等用户定义类型的未定义行为。这是因为 Index 中的重载运算符被视为函数。根据 C ISO 标准,函数求值在函数参数求值后引入一个序列点,在复制返回值后引入另一个序列点。

序列点和重载运算符

在 i = i 的情况下,表达式 i 在作为参数传递给运算符 = 之前先进行计算。这意味着在对 i 求值之后存在一个序列点,确保对象 i 在连续的序列点之间仅被修改一次。

因此,表达式 i = i 对于用户定义类型(如 Index)是等效的编写 i.operator =(i.operator ()); ,这是一个定义良好的表达式,没有未定义的行为。这同样适用于语法上更简单的表达式 i.add(i.inc());。

微妙的区别:

重要的是要注意 i = i 不是 C 语法意义上的表达式。相反,它是一个“语句表达式”,它是表达式和​​语句的语法组合。语句表达式与普通语句一样执行,但其结果也可以赋值给变量。

a[ i] = i

如果 a 是数组对于内置类型,表达式 a[ i] = i 会调用未定义的行为,因为左值 a[ i] 被求值两次:一次在表达式 i 中,另一次在赋值 i = 中i.

但是,如果 a 是重载下标运算符的用户定义类型,则表达式的行为可能会有所不同,具体取决于下标运算符的实现。例如,如果使用 const Index& operator[](Index i) 实现下标运算符,则表达式将是明确定义的,因为在调用下标运算符之前,左值 a[ i] 仅计算一次。

i 的有效性;

表达式 i;在 C 03 中定义良好,因为它等价于 ((i.operator ()).operator ()).operator ()。这是因为每个运算符引入了一个序列点,确保对象 i 在连续的序列点之间仅被修改一次。

以上是`i = i` 是否会在 C 中调用用户定义类型的未定义行为?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn