免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: angelanpan
打印 上一主题 下一主题

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

论坛徽章:
0
21 [报告]
发表于 2009-05-17 10:41 |只看该作者

回复 #19 beepbug 的帖子

>> 微妙的是,有时有例外。

是的,所以我也微妙地用了 many,而不是 (all) other。

论坛徽章:
0
22 [报告]
发表于 2009-05-17 10:43 |只看该作者
原帖由 langue 于 2009-5-16 17:26 发表
从某种意义上讲,C 语言不是高级语言,因为它具备许多高级语言无法完成的功能,就比如直接内存访问。

为了使 C 语言具有更大的灵活性,标准在一些实现细节上并没有作太多的规定,而是留给实现者来完成。

...

关于第一点,即使绕开mmu,也不能直接内存访问吗?

论坛徽章:
0
23 [报告]
发表于 2009-05-17 10:57 |只看该作者
原帖由 mik 于 2009-5-16 23:37 发表
那与 C 无关,与平台和系统相关。

不能描述为在 XXXX 下的 C 可以访问内存,这样就不对的。

是目标平台允不允许你直接访问内存的问题。

---------------------------------------

只要 OS 允许,你 ...


mik, 你理解错了。看我后一个回答。
这里说的是语言的特征,可以不可以直接访问main memory. 不是说的OS的什么物理内存虚拟内存。根本讨论的不是一回事。

论坛徽章:
0
24 [报告]
发表于 2009-05-17 11:01 |只看该作者
原帖由 思一克 于 2009-5-17 10:38 发表
main memory就是指内存。
讨论或区分一个语言是否有能力直接访问主内存,世界就是说一个语言有无指针(类似)的能力。和OS系统所谓内存虚实无关。

我们说汇编可以直接访问main memory
C也基本可以(通过指针)
BASIC FORTRAN不可以。
该结论和区别是语言的特征,和OS和内存保护等无关。
main memory不是指实存虚存之类的-----这不是语言涉及的范围。

不要被误解了。
分清楚作用范围和问题的层次,就不容易误解了。

1)如果你理解"main memory"也包括虚存,那我无话可说。
2)如果1)不成立,那我说,你的“我们说汇编可以直接访问main memory”也是错误的。在虚存里运行的进程都不行。你就是直接写机器码,它访问的仍然是虚存。当然,如果1)是你对,那2)也是你对。
3)“该结论和区别是语言的特征”,问题是MBASIC和其它BASIC给你捣乱。你可以去看看BASIC的PEEK和POKE两个关键字。“C可以通过指针直接访问内存”,这是个真命题,因为里面有“可以”一词。但,没有指针是不是就意味着不能直接访问呢?还是那句话:条条大道通罗马。说不定还有别的语言可以呢。“分清楚作用范围和问题的层次,就不容易误解了。”逻辑比较乱的思一克,喜欢用这样话压别人。其实,这样说文不对题的话,恰好说明你的思维有点乱。
好啦,你先去看看BASIC的PEEK和POKE吧。说空的没意思。

论坛徽章:
0
25 [报告]
发表于 2009-05-17 11:10 |只看该作者
原帖由 思一克 于 2009-5-17 10:57 发表

mik, 你理解错了。看我后一个回答。
这里说的是语言的特征,可以不可以直接访问main memory. 不是说的OS的什么物理内存虚拟内存。根本讨论的不是一回事。

1)你指出我的理解错了,你是对的。
2)不过关于这一点,是你理解错了。这个是不是语言的特征,是一回事,暂且不说。但是,即使是语言特征,也要受OS的制约。你是学C的,理该熟悉C的特征:在所有高级语言中,C是最受硬件平台和操作平台制约的语言。不用说这么“高级”的问题,即使是最“低级”的,数据长度,也是随平台而定的。

论坛徽章:
0
26 [报告]
发表于 2009-05-17 11:29 |只看该作者
原帖由 beepbug 于 2009-5-17 11:10 发表

1)你指出我的理解错了,你是对的。
2)不过关于这一点,是你理解错了。这个是不是语言的特征,是一回事,暂且不说。但是,即使是语言特征,也要受OS的制约。你是学C的,理该熟悉C的特征:在所有高级语言中, ...


讨论的是语言的能力,和OS不是一个层次的问题。
人说"汇编语言能直接访问main memroy",意思是汇编有这语句访问主内存,和什么上的汇编无关。不是说DOS上的汇编可以,LINUX上的就不可以。这里不涉及内存是物理的还是虚拟的问题。
分清讨论问题的层次就不容易被误导了。

论坛徽章:
0
27 [报告]
发表于 2009-05-17 11:44 |只看该作者
原帖由 思一克 于 2009-5-17 10:57 发表


mik, 你理解错了。看我后一个回答。
这里说的是语言的特征,可以不可以直接访问main memory. 不是说的OS的什么物理内存虚拟内存。根本讨论的不是一回事。


你大概也误会我的意思了,我本意反驳 beepbug 的“C 在 XXX 下可以访问内存,在 XXX 下不可以访问内存”这种观点。
----------------------------------------------
  所以我就说:同样的 C,为什么在 XXX 下可访问内存,在 XXX 下不可以访问内存,这是取决于 平台和 OS

    这与 C 无关(与 C 具不具有访问内存的能力无关)

 我在上个回复就开篇明义了。


BTW:讨论这个实在无聊,偶就不再参和

论坛徽章:
0
28 [报告]
发表于 2009-05-17 12:10 |只看该作者
这么硬拗,我只好退出。

论坛徽章:
0
29 [报告]
发表于 2009-05-17 12:51 |只看该作者
有直接访问main memory的语言就是汇编,高级语言主要是C. 其他没有。
这也是C和其他高级语言的主要区别。

BASIC的PEEK POKE是函数(类函数)。通过函数的不是直接访问。直接的意思是语句提供的操作能力,不是函数。BASIC没有提供这种能力。
函数本身不是语言的部分。如同printf不是C语言本身。如何区别? 实现printf不是设计C编译的人考虑的东西。

C和其它众多函数式语言的主要区别就是直接内存访问的能力。因为有这能力所以我们说C不是严格意义上的高级语言。

论坛徽章:
0
30 [报告]
发表于 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

后者就是先计算右边的参数,再计算左边的参数.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP