i=1,为什么 (++i)+(++i)=6?

源码

#include "stdio.h"int main(void)
{int i = 1;printf("%d\n",(++i) +(++i));return 0;
}

执行

weiqifa@bsp-ubuntu1804:~/c/undif$ gcc g.c && ./a.out
6
weiqifa@bsp-ubuntu1804:~/c/undif$

为什么出现这个鬼现象?

原因很简单,C语言的法律里面没有定义这条规格,这个属于C语言的未定义行为,也就是擦边球,什么是擦边球呢?就是这些行为不是错误的行为,法律没有明确定义的,所以就是擦边球。

它的执行顺序是这样的

int i = 1;
++i ;//i = 2
++i ;//i = 3
i + i ; //输出6

反汇编看看

weiqifa@bsp-ubuntu1804:~/c/undif$ gcc -S g.c
weiqifa@bsp-ubuntu1804:~/c/undif$ cat g.s.file   "g.c".text.p        .rodata
.LC0:.string "%d\n".text.globl  main.type   main, @function
main:
.LFB0:.cfi_startprocpushq   %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq    %rsp, %rbp.cfi_def_cfa_register 6subq    $16, %rspmovl    $1, -4(%rbp)addl    $1, -4(%rbp)addl    $1, -4(%rbp)movl    -4(%rbp), %eaxaddl    %eax, %eaxmovl    %eax, %esileaq    .LC0(%rip), %rdimovl    $0, %eaxcall    printf@PLTmovl    $0, %eaxleave.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE0:.size   main, .-main.ident  "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0".p        .note.GNU-stack,"",@progbits
weiqifa@bsp-ubuntu1804:~/c/undif$ ls

我们不用关注所有的代码,分析下面几行关键的

subq    $16, %rsp
movl    $1, -4(%rbp) //相当于 i = 1
addl    $1, -4(%rbp) //相当于 i +1
addl    $1, -4(%rbp) //相当于 i +1
movl    -4(%rbp), %eax // 把rbp寄存器传给eax寄存器
addl    %eax, %eax //相当于 i + i

看完这个代码后,应该知道为啥输出的是 6 了吧?

最后

我认为一个是编译器执行顺序的问题,反汇编无非就是搞清楚C的执行顺序,而且我认为研究这个是有意义的,不过有意义不代表可以这样写代码。

C本身是偏底层的东西,了解编译的原理和过程是非常重要的。

但是了解也不能这样瞎用,还是要遵守规则,要不然,这样导致的bug估计要害死很多人。

推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

嵌入式Linux

微信扫描二维码,关注我的公众号

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/467581.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android-HIDL实例解析

HIDL 简介“HAL interface definition language or HIDL (pronounced “hide-l”) is an interface description language (IDL) to specify the interface between a HAL and its users. It allows specifying types and method calls, collected into interfaces and package…

子矩阵(NOIP2014 普及组第四题)

描述 给出如下定义: 子矩阵:从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵(保持行与 列的相对顺序)被称为原矩阵的一个子矩阵。 例如,下面左图中选取第 2、4 行和第 2、4、5 列交叉位置的元素得到一个 2*3 …

linux spinlock/rwlock/seqlock原理剖析(基于ARM64)

背景Kernel版本:4.14ARM64处理器,Contex-A53,双核使用工具:Source Insight 3.5, Visio1. 概述吹起并发机制研究的进攻号角了!作为第一篇文章,应该提纲挈领的介绍下并发。什么是并发,…

爸爸都老了

今天是父亲节,早上韦泽楠去上绘画课,我睡了个回笼觉,一觉睡到了十一点。起来的时候老婆买了新鲜的荔枝和龙眼,当然我没有马上吃,我不是一个随便的男人,我刷了牙,洗了脸,再回到客厅慢…

java输出日志_java代码中如何正确使用loggger日志输出

java代码中如何正确使用loggger日志输出发布时间:2019-06-28作者:spider阅读(2980)当你遇到问题的时候,只能通过debug功能来确定问题,你应该考虑打日志,良好的系统,是可以通过日志进行问题定为的。使用slf4…

大学的多级放大电路,你交给老师了吗?

第一章 设计任务1.1项目名称:设计三极管多级音频放大电路本项目的主要内容是设计并实现三极管多级音频放大功能。该电路将所学习的三极管基本放大电路与功率放大电路有机结合。1.2项目设计说明(1)设计任务和要求使用常见的小功率三极管设计一…

第十四节TypeScript 联合类型

1、简介 联合类型可以通过管道(|)将变量设置多种类型,赋值时可以根据设置的类型来赋值。 注意:只能赋值指定的类型,如果赋值其它类型就会报错的。 2、创建联合类型的语法格式: Type1|Type2|Type3 实例&a…

Linux进程调度器-基础

背景Read the fucking source code! --By 鲁迅A picture is worth a thousand words. --By 高尔基说明:Kernel版本:4.14ARM64处理器,Contex-A53,双核使用工具:Source Insight 3.5, Visio1. 概述从这篇文章…

每天学习点--------第五天(2017-10-9) 摘要: 常用的集合

今天学习 java.util下面的软件包 包含 collection框架、遗留的coolection类、事件模型、日期和时间设施、国际化和各种工具类&#xff08;字符串标记生成器、随机数生成器和位数组&#xff09; 一、Collenction<.E> 接口 转载于:https://www.cnblogs.com/hanxue112253/p/…

Linux内存,先看这篇文章

内存大小计算我们拿32位系统来举个栗子2^32 ‭4,294,967,296‬ bytes‭4,294,967,296‬ bytes / 1024 ‭4,194,304‬ kbytes4,194,304‬ kbytes / 1024 ‭4,096‬ M‭4,096‬ M /1024 4G物理内存如何分页&#xff1f;分段和分页计算机内存管理的两种方式&#xff0c;这里我…

cloudstack java api_CloudStack API编程指引

前言本文阐述为CloudStack编写新API或者更新已存在API时应遵循的约定和编程指引。参考文档(暂略)介绍当你需要为CS添加新的API时&#xff0c;需要创建一个Request类和Response类(或者在扩展CS API功能时它的API Responese已经定义的情况下重用已经存在的API Response类)。编写C…

在ODM公司要不要跳槽到创业公司

读者朋友提问&#xff1a; 发哥&#xff0c;我现在在手机odm公司做指纹模块做了两三个月&#xff0c;基本天天加班到十点以后&#xff0c;后面要被调到camera团队&#xff0c;但是从这几个月的经历来看&#xff0c;感觉学到的不多&#xff0c;代码都是供应商写的&#xff0c;很…

安卓系统应用启动流程分析

随着移动开发的兴起&#xff0c;安卓系统的重要性愈加突显。本文简要介绍安卓系统上应用启动流程&#xff0c;对于应用开发、系统定制以及性能优化人员来说&#xff0c;熟悉应用启动流程会使得在今后的工作中更加得心应手&#xff0c;做到知其然&#xff0c;知其所以然。本文主…

物联网通信协议全解析

随着物联网设备数量的持续增加&#xff0c;这些设备之间的通信或连接已成为一个重要的思考课题。通信对物联网来说十分常用且关键&#xff0c;无论是近距离无线传输技术还是移动通信技术&#xff0c;都影响着物联网的发展。而在通信中&#xff0c;通信协议尤其重要&#xff0c;…

【长沙集训】2017.10.10

Adore 1.1 问题描述 小 w 偶然间遇到了一个 DAG。 这个 DAG 有 m 层&#xff0c;第一层只有1个源点&#xff0c;最后一层只有1个汇点&#xff0c;剩下的每一层都有 k 个 节点。 现在小 w 每次可以取反第 i(1 < i < n − 1) 层和第 i 1 层之间的连边。也就是把原本从 (i,…

Linux中断子系统之Workqueue

背景说明Kernel版本&#xff1a;4.14ARM64处理器&#xff0c;Contex-A53&#xff0c;双核使用工具&#xff1a;Source Insight 3.5&#xff0c; Visio1. 概述Workqueue工作队列是利用内核线程来异步执行工作任务的通用机制&#xff1b;Workqueue工作队列可以用作中断处理的Bott…

给你准备的Linux启动流程

读者朋友提问&#xff1a; 昨天在后台看到一个读者朋友跟我说&#xff0c;发哥&#xff0c;你能不能讲一下嵌入式Linux的开机流程&#xff0c;然后我看了下&#xff0c;我是没有写过这方面的文章&#xff0c;所以&#xff0c;就有了这篇文章。回答&#xff1a;我们都知道pc指针…

Linus Torvalds:我们都老了,但Linux维护者真的很难找

Linux 之父Linus Torvalds非常担忧没人继续维护内核「真的很难找到维护者&#xff01;」在本周召开的Linux开源峰会与嵌入式大会上&#xff0c; VMware的首席开放源代码官Dirk Hohndel和Linux的创建者Linus Torvalds再次就Linux开发展开了远程对话讨论。左&#xff1a;Dirk Ho…

看printk引发的一点思考

在源码位置kernel/printk/函数原型asmlinkage __visible int printk(const char *fmt, ...) {printk_func_t vprintk_func;va_list args;int r;va_start(args, fmt);/** If a caller overrides the per_cpu printk_func, then it needs* to disable preemption when calling pr…

我毕业时候写的简历

写简历这个事情&#xff0c;一直是一个非常让人头疼的&#xff0c;在我看来&#xff0c;写简历并不是一件简单的事情&#xff0c;所以&#xff0c;现在是晚上一点钟&#xff0c;我倒腾了一个晚上&#xff0c;才有了这篇文章。我认为写简历有几个需要注意的地方&#xff0c;不啰…