免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 21181 | 回复: 4
打印 上一主题 下一主题

[C] C语言函数参数压栈顺序与求值顺序的问题 [复制链接]

论坛徽章:
0
1 [报告]
发表于 2009-05-16 17:00 |显示全部楼层
哈, Google给搜索到CU的老贴.

1) 确实是这样子,即使是同样的gcc版本,在Sparc上和在X86上就使用了不同的计算顺序,这个还没到压栈那一步呢
    Sparc是按照从左向右的Natrual order,而在X86上就正好反过来,我试了Sparc的gcc 2.95.2和X86, Fedora的gcc 2.95.2 与 gcc 4.4 ; 还好都是AT&T 风格的ASM, 否则看Intel的那个, 左右是反的...

2) 为什么要这样实现? 同一个gcc的 release为什么会针对不同平台做不同的处理顺序呢?

3) 为什么从左到右就压栈会比较有效率? 就是Pascal压栈模式?

4) gcc是否有调整参数可以去选择某种顺序?

2,3,4正在研究中, 欢迎大家指点..

论坛徽章:
0
2 [报告]
发表于 2009-05-16 19:00 |显示全部楼层
langue , Thanks!

关于Calling Convention,能不能帮忙提供一些Tips? 我来Study一下看有没有办法从Makefile的角度来让Code不依赖于具体的Convention就可以cross_platform.

论坛徽章:
0
3 [报告]
发表于 2009-05-16 22:29 |显示全部楼层
查了一下, CallingConvention只是讲了参数Push的顺序,还是和参数计算的顺序没有关系,请指教..?_
Calling convention is the name of the calling convention. __cdecl, __stdcall, __pascal and
__fastcall can be specified explicitly in C++ function declarations for compilers that support
these conventions
所以,即使限制了从右向左的CallingConvention,仍然不能保证参数计算的顺序,在Gcc的文档里面也没有相应的选项.
继续查..

论坛徽章:
0
4 [报告]
发表于 2009-05-17 14:02 |显示全部楼层
Following-up,
对于        printf("s1=%s s2=%s\n", try("123"), try("456"));

Sparc的结果是
LLC3:
        .asciz        "123"
        .align 8
.LLC4:
        .asciz        "456"
#...main: lable
#...Namely the register group "out" is utilized for out-going var
#   but they are more offen to be seen as temp var storage
        sethi        %hi(.LLC3), %o1  #reg out[1], %o1 to retrieve 22 high bits
        or        %o1, %lo(.LLC3), %o0 #reg out[0], %o0 to retrieve 10 low bits
        call        try, 0
         nop
        mov        %o0, %l0             #move the result to reg local[0]
        sethi        %hi(.LLC4), %o1  #store high 22b addr into reg out[1]
        or        %o1, %lo(.LLC4), %o0 #store whole 32b addr into reg out[0]
        call        try, 0
         nop
        mov        %o0, %o2             #move the result to reg out[2]
        sethi        %hi(.LLC2), %o1  #store the high 22b addr into reg out[1]
        or        %o1, %lo(.LLC2), %o0 #store the whole 32b addr into reg out[0]
        mov        %l0, %o1             #the 1st res of try() to out[1]
        #thus the argument sequence'd be
   #the const str in out[0],
   #the 1st try() res in out[1],
   #the 2nd try() res in out[2],   
   #如果一定要排序,从%o0到%o2是从左往右的顺序                                                                    
       
        call        printf, 0

同样版本gcc在LinuxOnX86上就是
LC1:
        .string "456"
.LC2:
        .string "123"
.LC3:
        .string "s1=%s s2=%s\n"
!... some lines
!... push op...
        movl    $.LC1, (%esp)  !put argument into %esp
                                            !X86上先算了最右边的参数
        call    try
        movl    %eax, %ebx     !put the temp result into %ebx
        movl    $.LC2, (%esp)
        call    try
        movl    %ebx, 8(%esp)  
        movl    %eax, 4(%esp)  !put in the temp result
        movl    $.LC3, (%esp)
        call    printf

后者就是先计算右边的参数,再计算左边的参数.

论坛徽章:
0
5 [报告]
发表于 2009-05-17 19:09 |显示全部楼层
不是这样的,可以参见我前面贴的ASM,

实际上很多RISC机器上跑的系统都是从左向右计算参数,

[descriptions from C99]
The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call.
EXAMPLE In the function call (*pf[f1()]) (f2(), f3() + f4()) the functions f1, f2, f3, and f4 may be called in any order. All side effects have to be completed before the function pointed to by pf[f1()] is called.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP