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

#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. Linux入门-7 Linux管道、重定向以及文本处理

    Linux管道.重定向以及文本处理 1 Linux多命令协作:管道及重定向 管道和重定向 2 Linux命令行文本处理工具 文件浏览 基于关键字搜索-grep 基于列处理文本-cut 文本统计-wc ...

  2. VSTO 开发

    http://www.cnblogs.com/yangecnu/category/499866.html http://www.cnblogs.com/brooks-dotnet/category/2 ...

  3. mysql服务器硬件配置选择参考

    这是在网上找的一个关于如何评估一个mysql服务器的硬件需求的文章,转载以备用 5 Minute DBA – Database Server Hardware Selection Posted on  ...

  4. Java实例---flappy-bird实例解析

    第一天: 实现背景图片和小鸟的动态飞行效果 package com.ftl.flappybird.day2; import java.awt.Color;//颜色 Color.class import ...

  5. Monster: half man, half beast and very scary.

    Monster: half man, half beast and very scary. 怪物,半人半兽很吓人.

  6. Mac下安装Spark

    1.Scala 官网下载scala安装包后解压,路径随意. 编辑/etc/bash_profile添加$SCALA_HOME并修改相应PATH 2.SSH无密码登陆 ssh-keygen -t rsa ...

  7. python BaseManager中register()的描述

    register(typeid[, callable[, proxytype[, exposed[, method_to_typeid[, create_method]]]]]) A classmet ...

  8. socket的双重属性

    1)api属性: 2)通信链路的端点属性.

  9. Mybatis和Mysql的Json类型

    Mysql5.7新增加了Json类型字段,但是目前Mybatis中并不支持 1.新建MybatisJsonTypeHandler.java import com.fasterxml.jackson.a ...

  10. luogu P2742 【模板】二维凸包

    嘟嘟嘟 没错,我开始学凸包了. 其实挺简单的. 前置技能: 1.极坐标系 2.向量叉积 1.极坐标系 就是一种二维坐标系.只不过两个坐标分别表示向量和极轴的角度和自身的长度.对于不同的问题,极轴可以自 ...