我们或多或少都有过,或者见过将赋值表达式参与运算的情况。这通常会伴随着一些意想不到的问题。今天我就见到了一段奇怪的代码:

#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语言中赋值表达式的返回值是什么?的更多相关文章

  1. 013_go语言中的函数多返回值

    代码演示 package main import "fmt" func vals() (int, int) { return 3, 7 } func main() { a, b : ...

  2. C/C++ 语言中的表达式求值

    在此,首先向裘老师致敬! 裘宗燕:C/C++ 语言中的表达式求值 经常可以在一些讨论组里看到下面的提问:“谁知道下面C语句给n赋什么值?” m = 1; n = m+++m++; 最近有位不相识的朋友 ...

  3. Swift2.0语言教程之函数的返回值与函数类型

    Swift2.0语言教程之函数的返回值与函数类型 Swift2.0中函数的返回值 根据是否具有返回值,函数可以分为无返回值函数和有返回值函数.以下将会对这两种函数类型进行讲解. Swift2.0中具有 ...

  4. 慕课网-Java入门第一季-7-3 Java 中无参带返回值方法的使用

    来源:http://www.imooc.com/code/1579 如果方法不包含参数,但有返回值,我们称为无参带返回值的方法. 例如:下面的代码,定义了一个方法名为 calSum ,无参数,但返回值 ...

  5. Java 中无参带返回值方法的使用

    如果方法不包含参数,但有返回值,我们称为无参带返回值的方法. 例如:下面的代码,定义了一个方法名为 calSum ,无参数,但返回值为 int 类型的方法,执行的操作为计算两数之和,并返回结果 在 c ...

  6. python中os.system()的返回值

    [python中os.system()的返回值] 如果第三方程序返回的是布尔型返回值,os.system会将true转为1,false转为0进行返回. 问题: /bin/xxx.py是一个返回码为1的 ...

  7. C/C++ 语言中的表达式求值(原文作者:裘宗燕)

    经常可以在一些讨论组里看到下面的提问:“谁知道下面C语句给n赋什么值?”m = 1; n = m+++m++;最近有位不相识的朋友发email给我,问为什么在某个C++系统里,下面表达式打印出两个4, ...

  8. c语言中的结构体为值类型,当把一个结构体赋值给另一个结构体时,为值传递

    #include <stdio.h> int main() { struct person { int age; }; }; //值传递,将p1中所有成员变量的值赋值个p2中对应的成员变量 ...

  9. c#中表达式的返回值是啥?

    今天在学javascript的时候发现它其中有一个语法是这样的(a="haha).length;这样也能够输出haha这个字符串的长度,然而我在使用c#的时候分行读取txt文本的时候也用这个 ...

随机推荐

  1. Exchange 接收连接器(Client、Default)区别,OUtlook实际测试

    CAS就是接收连接器(110,995): Server Config--Client Access:POP3 and IMAP4:POP3设置 HUB就是发送连接器(25,587) Server Co ...

  2. Python入门学习网址

    Python入门学习网址:http://www.runoob.com/python/python-install.html

  3. 沉淀再出发:kafka初探

    沉淀再出发:kafka初探 一.前言 从我们接触大数据开始,可能绕在耳边的词汇里面出现的次数越来越多的就包括kfaka了.kafka的设计初衷是希望作为一个统一的信息收集平台,能够实时的收集反馈信息, ...

  4. execl execv

    int execl(const char *path, const char *arg, ...); 函数说明 execl()其中后缀"l"代表list也就是参数列表的意思第一参数 ...

  5. python的进度条实现

    进度条最主要的问题就是所有字符全部在同一行,而且可以修改.然而当执行print语句的时候,python会在打印完这个语句的同时,在结尾加上换行‘\n’,这就导致在控制台下一旦被print之后就无法修改 ...

  6. 在Django中使用Q()对象

    转载于:  http://www.smallerpig.com/1000.html 问题 一般我们在Django程序中查询数据库操作都是在QuerySet里进行进行,例如下面代码: >>& ...

  7. Odoo权限控制

    转载请注明原文地址:https://www.cnblogs.com/cnodoo/p/9278734.html 一:Odoo中的权限设置主要有以下5种 1)菜单.报表的访问权限 Odoo可以设置菜单项 ...

  8. 20165302实验二java面向对象程序设计

    20165302实验二java面向对象程序设计 实验结果 提交点1 1.实验要求: 参考 (http://www.cnblogs.com/rocedu/p/6371315.html#SECUNITTE ...

  9. jquery mobile各类组件刷新方法

      1.Combobox or select dropdowns var myselect = $("#sCountry"); myselect[0].selectedIndex ...

  10. ThinkPHP5入门(四)----模板篇

    一.模板访问 1.没有参数传递 $view = new View(); return $view->fetch(); 此时默认访问的模板路径为:[模板文件目录]/当前控制器名(小写+下划线)/当 ...