不是钻牛角尖 只是好奇

donglq 2009-10-11 02:51:15
我刚试了试下面的代码,打出来是:1,0,1
int main()
{
int j=0;
printf("j=%d,j++=%d,j=%d\n",j,j++,j);
return 0;
}

请教之~
...全文
138 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
玖伍叁柒 2009-10-11
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 wendll 的回复:]
呵呵,这种贴见的很多了
结果跟编译器有关吧
j++式返回的是一个const的常量,为0
而printf在执行j++运算后才执行,此时j已经为1,于是产生你所述的结果
[/Quote]

printf在执行j++运算后才执行

这句话是重点
玖伍叁柒 2009-10-11
  • 打赏
  • 举报
回复
汇编之。。。
 int j=0; 
00FC13BE mov dword ptr [j],0
printf("j=%d,j++=%d,j=%d\n",j,j++,j);
00FC13C5 mov eax,dword ptr [j]
00FC13C8 mov dword ptr [ebp-0D0h],eax
00FC13CE mov ecx,dword ptr [j]
00FC13D1 add ecx,1
00FC13D4 mov dword ptr [j],ecx
00FC13D7 mov esi,esp
00FC13D9 mov edx,dword ptr [j]
00FC13DC push edx
00FC13DD mov eax,dword ptr [ebp-0D0h]
00FC13E3 push eax
00FC13E4 mov ecx,dword ptr [j]
00FC13E7 push ecx
00FC13E8 push offset string "j=%d,j++=%d,j=%d\n" (0FC5800h)
00FC13ED call dword ptr [__imp__printf (0FC82BCh)]
donglq 2009-10-11
  • 打赏
  • 举报
回复
刚才找了点资料,希望给有同意疑问的朋友们有所帮助,非原创

c/c++的函数参数压栈顺序.



为了这句话丢了很多次人.无所谓了,反正咱脸皮厚.

总结一下: 编译出来的c/c++程序的参数压栈顺序只和编译器相关!

下面列举了一些常见的编译器的调用约定

VC6:


调用约定 堆栈清除 参数传递
__cdecl 调用者 从右到左,通过堆栈传递
__stdcall 函数体 从右到左,通过堆栈传递
__fastcall 函数体 从右到左,优先使用寄存器(ECX,EDX),然后使用堆栈
thiscall 函数体 this指针默认通过ECX传递,其它参数从右到左入栈


__cdecl是C\C++的默认调用约定; VC的调用约定中并没有thiscall这个关键字,它是类成员函数默认调用约定;
C\C++中的main(或wmain)函数的调用约定必须是__cdecl,不允许更改;
默认调用约定一般能够通过编译器设置进行更改,如果你的代码依赖于调用约定,请明确指出需要使用的调用约定;

C++Builder6:


调用约定 堆栈清除 参数传递
__fastcall 函数体 从左到右,优先使用寄存器(EAX,EDX,ECX),然后使用堆栈 (兼容Delphi的register)
(register与__fastcall等同)
__pascal 函数体 从左到右,通过堆栈传递
__cdecl 调用者 从右到左,通过堆栈传递(与C\C++默认调用约定兼容)
__stdcall 函数体 从右到左,通过堆栈传递(与VC中的__stdcall兼容)
__msfastcall 函数体 从右到左,优先使用寄存器(ECX,EDX),然后使用堆栈(兼容VC的__fastcall)

上述资料来源于HouSisong的一篇文章:http://www.allaboutprogram.com/index.php?option=content&task=view&id=29&Itemid=31.
由于能力和资源有限,只能找到这些东西,主要的差异体现在fastcall上面,vc是前两个参数放入寄存器,后面的压栈,bcb是前3哥参数使用寄存器,
更有变态的,一个朋友朋友说有的参数超过7个以后前5个从左到右传递,后面的从右到走,上面说的不可不信,不可全信.
如何确定你的编译采用的那种顺序那?
#include <stdio.h>
int f(int i,int j,int k);
int main()
{
static int i=0;
f(i++,i++,i++);
return 0;
}

int f(int i,int j,int k)
{
int l;
int g;
printf("k=%d:[%x]\n",k,&k);
printf("j=%d:[%x]\n",j,&j);
printf("i=%d:[%x]\n",i,&i);
printf("___________\n");
printf("l:%x\n",&l);
printf("g:%x\n",&g);
}
看看k->i的地址的增长顺序和l->g的顺序是否相同,如果相同则是从右到左,否则从左到右.
PS:
本来通过打印参数的值来判断那个先入栈,结果被一个朋友批评了,
他说:压栈顺序和参数计算顺序不是一回事,所以还是看地址更有保证.
//看过的朋友当作笑谈吧。

曾经看到一篇文章上面说:c/c++参数压栈顺序是从右到左,pascal参数压栈是从左到右.

donglq 2009-10-11
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 steedhorse 的回复:]
引用 11 楼 donglq 的回复:
恩 看得懂 还有个疑问 为什么要等j++算出来再一起压栈呢 为什么不是接受一个数据就把他压进去

这些细枝末节语言标准中并没有明确的规定,所以你说的两种都是可以的,也都是“对”的,就看各种编译器作者的喜好了。
[/Quote]
Got it
3Q
晨星 2009-10-11
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 donglq 的回复:]
恩 看得懂 还有个疑问 为什么要等j++算出来再一起压栈呢 为什么不是接受一个数据就把他压进去
[/Quote]
这些细枝末节语言标准中并没有明确的规定,所以你说的两种都是可以的,也都是“对”的,就看各种编译器作者的喜好了。
donglq 2009-10-11
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 steedhorse 的回复:]
不知道你能否看懂我说的。
但我自己说了这一大堆还是觉得很没意义,因为这只是可能的解释之一。。。换句话说,说再多也是白说,也不一定是实际的情况。
况且从语言上来讲这个结果是不确定的。
[/Quote]

恩 看得懂 还有个疑问 为什么要等j++算出来再一起压栈呢 为什么不是接受一个数据就把他压进去
晨星 2009-10-11
  • 打赏
  • 举报
回复
这里的主要问题是:对于各个参数,求值和压栈的次序是不定的,可以采取求一个,压一个的次序,也可以待所有的求值完毕后再一次性把所有值压入栈中。而对于“求值”过程来说,像“j”这么简单的表达式,可以不采取任何动作。
所以出现101是可能的。
CrySleeper 2009-10-11
  • 打赏
  • 举报
回复
随便看看编译原理好了
晨星 2009-10-11
  • 打赏
  • 举报
回复
不知道你能否看懂我说的。
但我自己说了这一大堆还是觉得很没意义,因为这只是可能的解释之一。。。换句话说,说再多也是白说,也不一定是实际的情况。
况且从语言上来讲这个结果是不确定的。
晨星 2009-10-11
  • 打赏
  • 举报
回复
最简单的解释是,对于“j”,“j++”和“j”这三个参数表达式来说,由于第一个和第三个的“求值”过程不需要有实际的动作,因为,编译器就只对第二个表达式进行求值计算,待求完值后三个表达式的值都知道了,此时再把“求出来”的三个值压栈。但此时的j已非先前的j,所以造成了两个1。
注意后自增“j++”的求值,其含义是:将j加1,然后将加1之前的值作为此表达式的值。
donglq 2009-10-11
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 steedhorse 的回复:]
要想出一种解释很容易,但问题是真的没啥意义。
当然,你也可以看看编译器生成的汇编代码。
[/Quote]

是没什么意义 就是好奇 1,0,0 或者 0,0,1 很容易想通 1,0,1 就不怎么好想了

我也只是好奇 本人确实是不喜欢钻牛角尖的
wendll 2009-10-11
  • 打赏
  • 举报
回复
呵呵,这种贴见的很多了
结果跟编译器有关吧
j++式返回的是一个const的常量,为0
而printf在执行j++运算后才执行,此时j已经为1,于是产生你所述的结果
昵称很不好取 2009-10-11
  • 打赏
  • 举报
回复
Code::Blocks编译有下面的警告:
warning: operation on `j' may be undefined|
warning: operation on `j' may be undefined|
||=== Build finished: 0 errors, 2 warnings ===|

Code::Blocks下执行结果如下:
j=1,j++=0,j=0

Process returned 0 (0x0) execution time : 0.032 s
Press any key to continue.
晨星 2009-10-11
  • 打赏
  • 举报
回复
要想出一种解释很容易,但问题是真的没啥意义。
当然,你也可以看看编译器生成的汇编代码。
qqwx_1986 2009-10-11
  • 打赏
  • 举报
回复
还不是钻
昵称很不好取 2009-10-11
  • 打赏
  • 举报
回复
你换个编译器就会有不同的结果~~~~~~~

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧