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

#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. SQL连接的分类

    连接的分类 内连接 等值连接(INNER JOIN) 自然连接(NATURAL JOIN) 交叉连接(CROSS JOIN) 不等连接 外连接 左外连接(LEFT OUTER) 右外连接(RIGHT ...

  2. sqlserver-一次updlock和withnolock和with check option 的报错原因分析

    接口程序一直运行的很稳定,其中有一天进行了数据库的整改,导致程序不断报错, 报错信息如下 原因: 程序代码写入以下代码 select * from ViewName with(updlock) whe ...

  3. linux的pthread_self与gettid的返回值和开销的区别

    linux的pthread_self与gettid的返回值和开销的区别 linux的pthread_self与gettid的返回值和开销的区别 分类: 一些思考 2012-05-18 12:25 17 ...

  4. There was a problem confirming the ssl certificate: [SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:661) - skipping

    Could not fetch URL https://pypi.python.org/simple/xlrd/: There was a problem confirming the ssl cer ...

  5. [原]Ubuntu 下安装apache+PHP

    1.安装apache2 sudo apt-get install apache2 运行如下命令重启:sudo /etc/init.d/apache2 restart 在浏览器里输入http://loc ...

  6. UVA-1152-4 Values whose Sum is 0---中途相遇法

    题目链接: https://cn.vjudge.net/problem/UVA-1152 题目大意: 给出4个数组,每个数组有n个数,问有多少种方案在每个数组中选一个数,使得四个数相加为0. n &l ...

  7. Java并发案例03---生产者消费者问题02

    生产者消费者第二种情形 package com.maple.msb.one; public class ProducerConsumer { public static void main(Strin ...

  8. Inno Setup 安装

    Inno Setup 安装 一.软件下载:http://www.jrsoftware.org/isdl.php#qsp 二.下载后,双击进行安装(包括inno Setup Compiler和Inno ...

  9. Java集合源码 -- Map映射和Set集合

    Map接口 Map接口是有一个映射表, 存储键和值, 它提供了两个通用的接口HashMap 和 TreeMap HashMap 是散列映射表, 对键散列; Tree是树映射表, 对键进行排序,并将其组 ...

  10. No.7 - 使用 animate.css 实现一个优雅的登录框

    <!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content ...