Man*_*iri 1 c printf equality undefined-behavior assignment-operator
我有以下代码片段:
main( )
{
int k = 35 ;
printf ( "\n%d %d %d", k == 35, k = 50, k > 40 ) ;
}
Run Code Online (Sandbox Code Playgroud)
产生以下输出
0 50 0
Run Code Online (Sandbox Code Playgroud)
我不知道我理解的第一个值怎么printf来0.当值k与之比较时35,理想情况下它应该返回(并因此打印)1,但它如何打印为零?产生的其他两个值 - 50并且0都是正确的,因为在第二个值中,k的值被视为50,而对于第三个值,k的值(即35)被比较40.因为35 < 40,所以它打印0.
任何帮助将不胜感激,谢谢.
**更新**
在研究了关于这个主题的更多内容之后undefined behavior,我在一本关于C的书中看到了这一点,最后给出了源代码.
调用约定 调用约定表示在遇到函数调用时参数被传递给函数的顺序.这里有两种可能性:
C语言遵循第二顺序.
考虑以下函数调用:
fun (a, b, c, d ) ;
Run Code Online (Sandbox Code Playgroud)
在这个调用中,参数是从左向右还是从右向左传递并不重要.但是,在某些函数调用中,传递参数的顺序成为一个重要的考虑因素.例如:
int a = 1 ;
printf ( "%d %d %d", a, ++a, a++ ) ;
Run Code Online (Sandbox Code Playgroud)
看来这printf( )会输出1 2 3.然而事实并非如此.令人惊讶的是,它输出3 3 1.
这是因为C的调用约定来自right to left.也就是说,首先1通过表达式a++然后a递增到2.然后++a通过结果.也就是说,a增加到3然后通过.最后,传递最新值a,即3.因此在right to left order 1, 3, 3通过.一旦printf( )它们收集它打印在开展我们要求它,让他们印刷(而不是他们所传递的顺序)的.这样3 3 1打印出来.
**Source: "Let Us C" 5th edition, Author: Yashwant Kanetkar, Chapter 5: Functions and Pointers**
Run Code Online (Sandbox Code Playgroud)
无论这个问题是否重复,我发现这些新信息对我有帮助,所以决定分享.注意:这也支持Mr.Zurg在下面的评论中提出的索赔.
不幸的是,阅读那本书的所有人都完全错了.在C99标准草案显然使此代码未定义的行为.使用Wikipedia条目快速检查未定义的行为包含一个类似的示例,并将其标识为未定义.我不会留下它,但还有其他容易获得的来源,这是正确的,而不必诉诸标准.
那标准说的是什么?在6.5 表达第3段中说:
运算符和操作数的分组由语法表示.74)除了稍后指定的(对于函数调用(),&&,||,?:和逗号运算符),子表达式的评估顺序和顺序发生哪些副作用都是未指明的.
因此,除非指定了子表达式的评估顺序是未指定的,否则第10段的6.5.2.2 函数调用说:
函数指示符的评估顺序,实际参数和实际参数中的子表达式是未指定的,但在实际调用之前有一个序列点.
所以在你的例子中:
printf ( "\n%d %d %d", k == 35, k = 50, k > 40 ) ;
^ ^ ^ ^
1 2 3 4
Run Code Online (Sandbox Code Playgroud)
1 to 4可以按任何顺序评估子表达式,我们无法知道每个子表达式的副作用何时发生,尽管我们知道它们都必须在实际调用函数之前生效.
因此k = 50可以在第一个或最后一个或任何地方进行评估,无论何时进行评估,更改值的副作用都k可以在执行实际功能之后立即进行.这意味着结果是不可预测的,可以想象在不同的执行期间改变变化.
接下来我们必须解决这是如何成为未定义的行为.6.5第2节中对此进行了说明,其中说:
在前一个和下一个序列点之间,一个对象的存储值最多只能通过表达式的计算来修改一次.72)此外,先前的值应该是只读的,以确定要存储的值.73)
因此,在您的示例中,我们不会k多次修改,但除了确定要存储的值之外,我们还使用先前值来执行其他操作.那么未定义行为的含义是什么?在未定义行为的定义中,标准说:
可能的未定义行为包括完全忽略具有不可预测结果的情况,在转换或程序执行期间以环境特征(有或没有发出诊断消息)的特定文档执行,终止翻译或执行(发布时)一条诊断信息).
因此编译器可以忽略它,或者也可能产生不可预测的结果,这涵盖了相当多的不良行为.臭名昭着地说:
当编译器遇到[给定的未定义构造]时,让恶魔飞出你的鼻子是合法的
这对我来说听起来很不可取.
| 归档时间: |
|
| 查看次数: |
420 次 |
| 最近记录: |