C语言中赋值表达式的返回值是什么?
我们或多或少都有过,或者见过将赋值表达式参与运算的情况。这通常会伴随着一些意想不到的问题。今天我就见到了一段奇怪的代码:
#include<stdio.h>
int main()
{
int a =;
int b = (a=)+(a=);
printf("%d %d\n",a,b);
return ;
}
乍一看,似乎答案很明朗,按照顺序运算之后,a的值是3,b的值是5.有经验的程序员肯定会一眼看出,这里的计算过程是一个未定义行为(Undefined behavior).在这里简单来说就是:无法确定哪一个括号里的表达式会先执行。
括号只能改变运算符的结合律,不能改变表达式的求值顺序。这个顺序是取决于编译器的。所以a的值是2还是3是不能确定的。
这段代码在gcc(Ubuntu)下得到的结果是
而在clang(Mac)下运行的结果是
为什么会这样呢? 这是怎么一回事呢?
查看它们生成的汇编代码
gcc
...
movl $, -(%rbp) // a=
movl $, -(%rbp) // a =
movl $, -(%rbp) //a =
movl -(%rbp), %eax // eax = a
addl %eax, %eax //eax = eax + eax
movl %eax, -(%rbp) // b = eax
... clang
...
movl $, -(%rbp)
movl $, -(%rbp) // a =
movl $, -(%rbp) // a =
movl $, -(%rbp) // b =
...
在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
//所以直接得到了赋值符号右边表达式值之和
由此得出结论:赋值表达式的返回值为赋值符号右边的值。
但在某些特殊情况下,使用某些编译器可能无法得到想要的结果。所以我们应当尽量避免使用赋值表达式的值参与运算。
注意:虽然在两个例子中,a的值都是3,但这并不意味着表达式的求值顺序是从左往右的。
有关编译器求值顺序的详细内容可以参考这篇文章
C语言中赋值表达式的返回值是什么?的更多相关文章
- 013_go语言中的函数多返回值
代码演示 package main import "fmt" func vals() (int, int) { return 3, 7 } func main() { a, b : ...
- C/C++ 语言中的表达式求值
在此,首先向裘老师致敬! 裘宗燕:C/C++ 语言中的表达式求值 经常可以在一些讨论组里看到下面的提问:“谁知道下面C语句给n赋什么值?” m = 1; n = m+++m++; 最近有位不相识的朋友 ...
- Swift2.0语言教程之函数的返回值与函数类型
Swift2.0语言教程之函数的返回值与函数类型 Swift2.0中函数的返回值 根据是否具有返回值,函数可以分为无返回值函数和有返回值函数.以下将会对这两种函数类型进行讲解. Swift2.0中具有 ...
- 慕课网-Java入门第一季-7-3 Java 中无参带返回值方法的使用
来源:http://www.imooc.com/code/1579 如果方法不包含参数,但有返回值,我们称为无参带返回值的方法. 例如:下面的代码,定义了一个方法名为 calSum ,无参数,但返回值 ...
- Java 中无参带返回值方法的使用
如果方法不包含参数,但有返回值,我们称为无参带返回值的方法. 例如:下面的代码,定义了一个方法名为 calSum ,无参数,但返回值为 int 类型的方法,执行的操作为计算两数之和,并返回结果 在 c ...
- python中os.system()的返回值
[python中os.system()的返回值] 如果第三方程序返回的是布尔型返回值,os.system会将true转为1,false转为0进行返回. 问题: /bin/xxx.py是一个返回码为1的 ...
- C/C++ 语言中的表达式求值(原文作者:裘宗燕)
经常可以在一些讨论组里看到下面的提问:“谁知道下面C语句给n赋什么值?”m = 1; n = m+++m++;最近有位不相识的朋友发email给我,问为什么在某个C++系统里,下面表达式打印出两个4, ...
- c语言中的结构体为值类型,当把一个结构体赋值给另一个结构体时,为值传递
#include <stdio.h> int main() { struct person { int age; }; }; //值传递,将p1中所有成员变量的值赋值个p2中对应的成员变量 ...
- c#中表达式的返回值是啥?
今天在学javascript的时候发现它其中有一个语法是这样的(a="haha).length;这样也能够输出haha这个字符串的长度,然而我在使用c#的时候分行读取txt文本的时候也用这个 ...
随机推荐
- C指针和数组
一.指针 指针就是地址,指针变量是用来存放地址的变量,把谁的地址存放在指针变量中,就说此指针变量指向谁. 二.数组 1.一维数组 一维数组名代表数组首元素的地址,因此 *a=a[0]; &:取 ...
- 多变量线性回归 matlab
%multivariate_linear_regression data=load('data.txt'); x=data(:,1:2); y=data(:,3); m=length(x(:,1)); ...
- Java基础知识强化之集合框架笔记76:ConcurrentHashMap之 ConcurrentHashMap简介
1. ConcurrentHashMap简介: ConcurrentHashMap是一个线程安全的Hash Table,它的主要功能是提供了一组和Hashtable功能相同但是线程安全的方法.Conc ...
- java @XmlTransient与@Transient区别
1.@XmlTransient a.@XmlTransient 注解解决 JavaBean 属性名称与字段名称之间的名称冲突,或者用于防止字段/属性的映射 b.阻止将 JavaBean 属性映射到 X ...
- nd.array.where
http://mxnet.apache.org/api/python/ndarray/ndarray.html#mxnet.ndarray.where Return the elements, eit ...
- javascript学习2
上次我们了解到 JavaScript提供了一组以window为核心的对象,实现了对浏览器窗口的访问控制.JavaScript中定义了6种重要的对象: window对象 表示浏览器中打开的窗 ...
- [NOIP2016]换教室(概率期望$DP$)
其实吧我老早就把这题切了--因为说实话,这道题确实不难啊--李云龙:比他娘的状压DP简单多了 今天我翻以前在Luogu上写的题解时,突然发现放错代码了,然后被一堆人\(hack\)--蓝瘦啊\(ORZ ...
- 接口测试Jmeter+Fiddler组合
接口测试Jmeter+Fiddler组合 在使用完Jmeter在做接口测试之后,个人感觉Jmeter比loadrunner好用,原因是界面操作更加直观,不必像loadrunner在写接口请求函数的时候 ...
- HDU 2072(字符串的流式操作,学习了)
传送门: http://acm.hdu.edu.cn/showproblem.php?pid=2072 单词数 Time Limit: 1000/1000 MS (Java/Others) Me ...
- lwip 2.0.3 DNS 域名解析 使用
1. 在 lwipopts.h 中 #define LWIP_DNS 1 /* 使能 DNS 服务器的功能 ,2018年1月8日21:16:20,suozhang */ #define LWIP_ ...