跳至主要内容

关于我

这里暂时空空如也

此博客中的热门博文

测试博文

这是我的第一篇博文。

C语言中赋值表达式的返回值是什么?

我们或多或少都有过,或者见过将赋值表达式参与运算的情况。这通常会伴随着一些意想不到的问题。今天我就见到了一段奇怪的代码:
#include<stdio.h> int main() { int a =5; int b = (a=2)+(a=3); printf("%d %d\n",a,b); return 0; } 乍一看,似乎答案很明朗,按照顺序运算之后,a的值是3,b的值是5.有经验的程序员肯定会一眼看出,这里的计算过程是一个未定义行为(Undefined behavior).在这里简单来说就是:无法确定哪一个括号里的表达式会先执行。
括号只能改变运算符的结合律,不能改变表达式的求值顺序。这个顺序是取决于编译器的。所以a的值是2还是3是不能确定的。
这段代码在gcc(Ubuntu)下得到的结果是
3 6 而在clang(Mac)下运行的结果是
3 5为什么会这样呢? 这是怎么一回事呢?
查看它们生成的汇编代码gcc ... movl $5, -8(%rbp) // a=5 movl $2, -8(%rbp) // a = 2 movl $3, -8(%rbp) //a = 3 movl -8(%rbp), %eax // eax = a addl %eax, %eax //eax = eax + eax movl %eax, -4(%rbp) // b = eax ...
clang ... movl $5, -8(%rbp) movl $2, -8(%rbp) // a = 2 movl $3, -8(%rbp) // a = 3 movl $5, -12(%rbp) // b = 5 ...
在gcc的理解中a = (b=c) //会被改写成 b=c a=b //所以对于 a = (b=c)+(d=e) //会被改写成 b = c d = e a = b+d //当b和d为同一个值的时候,变量空间被复用了, 在clang的理解中a = (b=c)+(d=e) //被改写成了 i=b=c j=d=e a=i+j //所以直接得到了赋值符号右边表达式值之和 由此得出结论:赋值表达式的返回值为赋值符号右边的值。
但在某些特殊情况下,使用某些编译器可能无法得到想要的结果。所以我们应当尽量…

C语言中while语句里使用scanf的技巧

今天友人和我讨论了一段代码,是HDU的OJ上一道题目的解,代码如下
#include<stdio.h> { int a,b; while(~scanf("%d%d",&a,&b)) { printf("%d\n",a+b); } return 0; } 起初,我以为代码中while语句里的按位取反运算符写错了,应该是逻辑非运算符。
这时我在Quora上找到了类似的问题,我对其中一篇答案做了修改和翻译:
查阅scanf函数的man手册,关于返回值的说明如下
函数返回按照格式成功匹配并读入的输入项数量,并且可能会返回一个小于输入项总数的数字,而在匹配失败的情况下,甚至可能返回0。 如果在第一次成功读入或者发生匹配错误之前收到输入结束信号,将会返回EOF。在遇到读入错误的时候,也会返回EOF。 在上面的代码里,scanf的返回值可能是0,1,2或者EOF。
对0,1,2进行按位取反得到的都是非零值,此时while循环会继续执行。
在大多数环境里,EOF被定义为值为-1的常量,进行按位取反后得到的值为0.此时while循环将会结束。
综上所述,这个while语句可以不断从输入流读入数据,直到输入流结束,循环也就结束。
值得一提的是,这种用法仅仅在EOF被定义为-1的环境下有效,而且可读性很差。所以应该尽量避免使用它。
在Linux和OS X里,你可以通过Ctrl+D来发送一个输入结束信号,在Windows里你需要使用Ctrl+Z。

参考资料:
Quora上的回答
scanf(3)