C语言提问
#include<stdio.h>main(){inti=8;printf("%d,%d,%d,%d,%d,%d\n",++i,--i,i++,i--,-i++,-i--...
#include <stdio.h>
main()
{
int i=8;
printf("%d,%d,%d,%d,%d,%d\n",++i,--i,i++,i--,-i++,-i--);
}
第一个数字为什么不是9啊? 展开
main()
{
int i=8;
printf("%d,%d,%d,%d,%d,%d\n",++i,--i,i++,i--,-i++,-i--);
}
第一个数字为什么不是9啊? 展开
4个回答
展开全部
这个问题非常的精妙。我给出一个能够解释的通的答案(不一定正确)。首先需要知道printf是一个函数,而函数的参数入栈的顺序。就是执行的时候,是如何被调用的。
需要学习的知识点:函数调用约定。如果你不知道程序是如何调用printf这个函数的,这个问题你就无法理解。简单的说,在调用函数之前,我们要保留“现场”,因为我们知道,程序执行的时候,是要“进入”函数中去的,等函数执行完了,回到原来的执行的地方,继续向下。
这个过程,C语言是从右向左压参数的。
还有一个问题,就是i++,++i的区别。在函数调用时,i++先入栈,后自增计算。++i是先自增计算,后入栈。
现在有了这些知识点,我们来理解这个程序:
计算机申请了一块内存,名字是i, 是int型的,里面的值是 8.
现在,调用了一个函数,这个函数有很多参数,其中有六个参数是我们要打印的,每个参数就是一块内存。它们没有名字,不像i。我们暂时就叫他们一二三四五六
从右向左, 我们开始把i内存中的值 转移 到 一二三四五六 中。转移的过程中,只有自增自减是影响i这块内存中的值,而其他计算是只影响这个计算目标内存的值。i++的目标内存就是i。
在处理之前,先运算一二的自增自减,所以i的值不变,是8.
分析六: -i--,这个计算的目标内存是六,所以六中的值是-8,然后i中进行自减,此时i这块内存的值变为7.
分析五: -i++, 五这块内存中的就是-7,而i这快内存中又变成了8.
分析四: 四中 是8, i又变成了 7
分析三: 三自然是7 ,然后i++,i这块内存中又变成了8.
一和二 自然都是8了,因为 自增自减 早就运算完了。
---------------------------------------------------------------
这个就是一个解释,我瞎猜测的,不一定这样,要真知道,你要去看看汇编以后的代码。
最麻烦的就是一直用i这块内存,所以写代码的时候还是要注意啊
-----------------------------------------------------------------
函数调用约定(Calling Convention)
函数调用约定不仅决定了发生函数调用时函数参数的入栈顺序,还决定了是由调用者函数还是被调用函数负责清除栈中的参数,还原堆栈。函数调用约定有很多方 式,除了常见的__cdecl,__fastcall和__stdcall之外,C++的编译器还支持thiscall方式,不少C/C++编译器还支持 naked call方式。这么多函数调用约定常常令许多程序员很迷惑,到底它们是怎么回事,都是在什么情况下使用呢?下面就分别介绍这几种函数调用约定。
1.__cdecl
编译器的命令行参数是/Gd。__cdecl方式是C/C++编译器默认的函数调用约定,所有非C++成员函数和那些没有用__stdcall或__fastcall声明的函数都默认是__cdecl方式,它使用C函数调用方式,函数参数按照从右向左的顺序入栈,函数调用者负责清除栈中的参数, 由于每次函数调用都要由编译器产生清除(还原)堆栈的代码,所以使用__cdecl方式编译的程序比使用__stdcall方式编译的程序要大很多,但是 __cdecl调用方式是由函数调用者负责清除栈中的函数参数,所以这种方式支持可变参数,比如printf和windows的API wsprintf就是__cdecl调用方式。对于C函数,__cdecl方式的名字修饰约定是在函数名称前添加一个下划线;
需要学习的知识点:函数调用约定。如果你不知道程序是如何调用printf这个函数的,这个问题你就无法理解。简单的说,在调用函数之前,我们要保留“现场”,因为我们知道,程序执行的时候,是要“进入”函数中去的,等函数执行完了,回到原来的执行的地方,继续向下。
这个过程,C语言是从右向左压参数的。
还有一个问题,就是i++,++i的区别。在函数调用时,i++先入栈,后自增计算。++i是先自增计算,后入栈。
现在有了这些知识点,我们来理解这个程序:
计算机申请了一块内存,名字是i, 是int型的,里面的值是 8.
现在,调用了一个函数,这个函数有很多参数,其中有六个参数是我们要打印的,每个参数就是一块内存。它们没有名字,不像i。我们暂时就叫他们一二三四五六
从右向左, 我们开始把i内存中的值 转移 到 一二三四五六 中。转移的过程中,只有自增自减是影响i这块内存中的值,而其他计算是只影响这个计算目标内存的值。i++的目标内存就是i。
在处理之前,先运算一二的自增自减,所以i的值不变,是8.
分析六: -i--,这个计算的目标内存是六,所以六中的值是-8,然后i中进行自减,此时i这块内存的值变为7.
分析五: -i++, 五这块内存中的就是-7,而i这快内存中又变成了8.
分析四: 四中 是8, i又变成了 7
分析三: 三自然是7 ,然后i++,i这块内存中又变成了8.
一和二 自然都是8了,因为 自增自减 早就运算完了。
---------------------------------------------------------------
这个就是一个解释,我瞎猜测的,不一定这样,要真知道,你要去看看汇编以后的代码。
最麻烦的就是一直用i这块内存,所以写代码的时候还是要注意啊
-----------------------------------------------------------------
函数调用约定(Calling Convention)
函数调用约定不仅决定了发生函数调用时函数参数的入栈顺序,还决定了是由调用者函数还是被调用函数负责清除栈中的参数,还原堆栈。函数调用约定有很多方 式,除了常见的__cdecl,__fastcall和__stdcall之外,C++的编译器还支持thiscall方式,不少C/C++编译器还支持 naked call方式。这么多函数调用约定常常令许多程序员很迷惑,到底它们是怎么回事,都是在什么情况下使用呢?下面就分别介绍这几种函数调用约定。
1.__cdecl
编译器的命令行参数是/Gd。__cdecl方式是C/C++编译器默认的函数调用约定,所有非C++成员函数和那些没有用__stdcall或__fastcall声明的函数都默认是__cdecl方式,它使用C函数调用方式,函数参数按照从右向左的顺序入栈,函数调用者负责清除栈中的参数, 由于每次函数调用都要由编译器产生清除(还原)堆栈的代码,所以使用__cdecl方式编译的程序比使用__stdcall方式编译的程序要大很多,但是 __cdecl调用方式是由函数调用者负责清除栈中的函数参数,所以这种方式支持可变参数,比如printf和windows的API wsprintf就是__cdecl调用方式。对于C函数,__cdecl方式的名字修饰约定是在函数名称前添加一个下划线;
展开全部
++i是本次运算结束后i才自增,,——i也一样,当时值 不变,到下一步时才改变
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
这是运算的优先级问题:
printf中的运算是从后往前算的
所以计算是先从-i--开始,输出是-8
然后计算-i++,输出是-7
然后是i--,输出是8
然后的大家就都知道了~
printf中的运算是从后往前算的
所以计算是先从-i--开始,输出是-8
然后计算-i++,输出是-7
然后是i--,输出是8
然后的大家就都知道了~
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
2010-08-21
展开全部
这个题是运算的优先级问题, 应该从右向左计算。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询