关于自增运算符

昨天参加智邮普创的面试,发现自己c语言好渣啊,先就昨天的一个问题学习一下,然后这周要不停学c来面对如果还有的二面了。

先通过一道面试题引入

int main(void) {

int a=3;

int b=0;

b=(++a)+(++a)+(++a);

printf(” %d %d \n”, a, b);

return 0;

}

面试的时候以为答案是15,结果被学长问有没有在电脑上敲过,刚刚敲了一遍发现是16,然后百度了一下大概知道了是怎么计算的。++a是一个有副作用的表达式,这段代码在不同的编译器的解释也是不一样的。如果按照平常的理解,似乎是4+5+6=15,但是在gcc和vc编译下都是16,在网上发现有的人在其他编译器下敲出来是18。

结果为16的情况是:先将变量a自增了两次,然后相加,最后再自增一次再和前面的和相加得出最后结果。

那在我理解看,++a先自增后使用(这里的使用理解为两项相加即为使用了)。

也就是第一个a自增后要使用,就是要和第二项相加,此时第二项也为++a,所以它也要先自增再使用(这里的使用即为与第一项求和),这时a在存储器中已经变化为5,然后需要使用,即将前两项求和结果为10,然后加最后一项,最后一项需要先自增为6再求和,答案为16。

如果这个逻辑成立,那么a++就可以理解为先使用后自增。

但是当我输入b=(++a)+(a++)+(a++)来证明我的理解时,如果按照上述逻辑,应该是4+4+5(即在(++a)+(a++)完成后可以算是使用了,然后a自增为5),结果应该为13,可执行后发现结果为12而不是13,那就说明a++的使用是以整个表达式为单位。

也就是a++的先使用后自增这里的使用理解为整个表达式执行完即为使用了。我计算了b=(a++)+(a++)+(a++)结果为9,好像猜想是对的。

最后,我结合两种情况敲入了b=(++a)+(a++)+(++a)+(++a);这样一个表达式,按照我的理解来分析这个式子:第一项a先自增为4,然后它要使用自增之后的值,也就是与第二项相加,第二项a先使用,也就是4+4=8,这个时候第二项的自增操作需要等整个表达式进行完后再进行,因为前文分析过a++的使用后自增是以表达式为单位判定的。这样继续第三项a先自增,然后使用,就是与之前计算的和相加,即5+8=13。最后一项b先自增为6再使用,即6+13=19。这时第二项的a++执行自增操作,a变为7。经过vc和dev实际验证,发现结论正确!

这样,基本证实了在gcc编译器下自增操作符的运算规则,但是在TC编译器下,编译器对b=(++a)+(++a)+(++a)的理解为6+6+6,这里不再赘述。

在平时使用中,是要避免使用这些带有副作用的表达式的,我也是因为面试题才研究了一下,关于c中表达式的求值顺序,我推荐阅读下面这篇文章https://bbs.csdn.net/topics/370153775

原文地址:https://www.cnblogs.com/wxylyw/p/9073505.html

时间: 2024-10-12 04:21:38

关于自增运算符的相关文章

C语言杂谈(二)自增运算符++与间接访问运算符*的结合关系和应用模式

自增运算符++有前缀和后缀两种,在搭配间接访问运算符*时,因为顺序.括号和结合关系的影响,很容易让人产生误解,产生错误的结果,这篇文章来详细分析一下这几种运算符的不同搭配情况. ++.--和*的优先级顺序 在C语言运算符的优先级顺序中,后缀的++和--运算符运算优先级16,结合关系是从左到右:简介访问运算符*.前缀++和--运算符运算优先级15,结合关系是从右到左.根据这个关系,可以分析出不同情况下的应用.为了更直观的体现,有以下的例子. 举例说明 有数组a[5],值分别为10,11,12,13

一个由自增运算符以及C语法顺序细节引起的bug

 一.问题描述 在编写modbus代码时发生一件由语法细节引起的bug,起因是自增运算符以及C语法顺序. 输入的数据是2233=0X08B9,高低字节顺序是0x08 0xB9, 使用modbus poll向92寄存器写入十进制数据2233. 但是经过(*reg++)*256+(reg++)之后,结果变成了0xB908. 检查内存也是0xB908. 说明reg_value写入了错误的数. 二.问题调查 反汇编后查看. 1)LDRB R2,[R5],#0X01 --> 把R5数据的低字节放入R2,并

C#自增运算符(++)

一.C#自增运算符(++) 自增运算符(++)是将操作数加1. 1. 前缀自增运算符 前缀自增运算符是“先加1,后使用”.它的运算结果是操作数加1之后的值. 例如: ++x;  // 前缀自增运算符 2. 后缀自增运算符后缀自增运算符是“先使用,后加1”.它的运算结果是操作数加1之前的值. 例如: x++;  // 后缀自增运算符 二.提示 自增运算符(++)适用于数值和枚举类型. 三.示例 using System;using System.Collections.Generic;using

C++重载自增运算符的效率问题

C++规定后缀形式有一个int类型参数,当函数被调用时,编译器传递一个0做为int参数的值给该函数. increment的前缀形式表示“增加然后取回”,后缀形式表示“取回然后增加”. 1 #include "stdafx.h" 2 #include "assert.h" 3 class A 4 { 5 public: 6 A(int i) 7 :m_i(i) 8 { 9 } 10 // ++i 11 A& operator++() 12 { 13 ++m_i

*p++与(*p)++与*(p++)------自增运算符常见误区

自增运算符(++) 自增\自减运算符分为前缀形(++a)和后缀形(a++),这里重点分析自增 大部分人对前缀和后缀的理解一般是,前缀形式是先++再使用(先变后用),后缀形式是先使用再++(先用后变)   (tips:自增运算符只能作用于变量,而不能作用于变量或表达式,例:(i+j)++就是非法的) 先来说一下一般情况 1 main() 2 { 3 int a = 3; 4 int b; 5 6 b = a++; 7 printf("%d", b); 8 } 上面这种应该大部分人都会,属

自增运算符

// // main.c // c自增运算符 // // Created by mac on 2019/4/9. // Copyright ? 2019年 mac. All rights reserved. // #include <stdio.h> int main(int argc, const char * argv[]) { int count=1; count++; count=5; int i=8; int y,b=3; y=(++b)+(b++);//8 printf("

printf中的自增运算符

前言 文中均设i=5,汇编代码:movl $5, -4(%rbp) // 将5赋值给rdp向下偏移4个指针的头指针(i) 在装用gcc环境的PC下,可以使用gcc -S -o assembly.S yourcodefile.c 打印汇编代码.首先打印出简单自增运算的汇编代码: i++; 的汇编代码 在早版本的编译器中可能是如下表达形式,而在最新版的gcc中,i++;与++i;的汇编代码是一样的. movl -4(%rbp), %eax // 将i赋值给ax寄存器, ax=5 leal 1(%ra

C语言中指针和自增运算符结合时的运算顺序问题

在C语言中,当指针运算符和++或者–结合时很容易分不清运算顺序,在这里总结一下,下面一共分析6中组合: * p++,(* p)++,* (p++),++* p,++( * p), * (++p). 先看段代码以及输出: #include<stdio.h> int main() { int a[3]={1,3,5}; int *p=a; printf("----------------1----------------\n"); printf("%d\n"

关于C的自增运算符

先看下边的一段代码 1 #include<stdio.h> 2 int main() 3 { 4 int i=3,j,k; 5 6 j=i++; 7 k=++i; 8 printf("i=%d,j=%d,k=%d\n",i,j,k); 9 printf("%d\n",-i++); 10 printf("%d,%d,%d,i,i++,i++); 11 return 0; 12 } 前两个输出函数应该比较简单,但是第三个输出函数输出的是: 8,7,