免费注册 查看新帖 |

Chinaunix

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

[C] 关于栈传递参数的问题--腾讯笔试题 [复制链接]

论坛徽章:
0
21 [报告]
发表于 2013-04-17 10:45 |只看该作者
回复 1# ilogo1

不同平台及实现可能结果不一样
输出 102应该是这样的

sizeof(int)=4
sizeof(long long)=8
栈分配如下:
低                              高
03 00 00 00 00 00 00 00       
02 00 00 00 00 00 00 00
01 00 00 00 00 00 00 00

printf根据格式%d%d%d只取了这连续的12个字节

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
22 [报告]
发表于 2013-04-17 10:48 |只看该作者
回复 20# hellioncu

x64 LINUX平台
        long a=0x31;
        long b=0x32;
        long c=0x33;
        printf("%c%c%c\r\n",a,b,c);

编译警告:

test.c:14: 警告:格式 ‘%c’ 需要类型 ‘int’,但实参 2 的类型为 ‘long int’
test.c:14: 警告:格式 ‘%c’ 需要类型 ‘int’,但实参 3 的类型为 ‘long int’
test.c:14: 警告:格式 ‘%c’ 需要类型 ‘int’,但实参 4 的类型为 ‘long int’

编译后运行输出:
123

并没有将a,b,c的高低双字组合,而是正常输出了a,b,c的低双字
汇编代码中,a、b、c都是8字节压栈
若将abc都改成int类型,则a、b、c都是4字节压栈
无论是4字节压栈还是8字节压栈,printf输出结果都是字符'1','2','3'

输出没有'0'出现,你的解释放在x64 LINUX上就说不通了

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
23 [报告]
发表于 2013-04-17 11:00 |只看该作者
C代码:
        long    a=0x31;
        long    b=0x32;
        long    c=0x33;

        printf("%c%c%c\r\n",a,b,c);

观察X64编译,相关汇编代码如下
.LC0:
        .string "%c%c%c\r\n"        movq    $49, -24(%rbp)
        movq    $50, -16(%rbp)
        movq    $51, -8(%rbp)
        movq    -8(%rbp), %rcx
        movq    -16(%rbp), %rdx
        movq    -24(%rbp), %rsi
        movl    $.LC0, %edi
        movl    $0, %eax
        call    printf

注意压栈是按照8字节压栈,但同时寄存器RSI、RDX、RCX也有值
按照AMD64 SYS V ABI规定,整数数值(含指针)传参顺序为:RDI、 RSI、 RDX、 RCX
call printf这句使得RIP跳转到printf函数的首地址,RDI是指向格式字符串"%c%c%c\r\n"的指针,
函数直接使用RSI、RDX、RCX的数值,完全没管栈里面的东西,也就没有神马高4字节低4字节组合的事情了

论坛徽章:
324
射手座
日期:2013-08-23 12:04:38射手座
日期:2013-08-23 16:18:12未羊
日期:2013-08-30 14:33:15水瓶座
日期:2013-09-02 16:44:31摩羯座
日期:2013-09-25 09:33:52双子座
日期:2013-09-26 12:21:10金牛座
日期:2013-10-14 09:08:49申猴
日期:2013-10-16 13:09:43子鼠
日期:2013-10-17 23:23:19射手座
日期:2013-10-18 13:00:27金牛座
日期:2013-10-18 15:47:57午马
日期:2013-10-18 21:43:38
24 [报告]
发表于 2013-04-17 11:12 |只看该作者
safedead 发表于 2013-04-17 10:48
回复 20# hellioncu

x64 LINUX平台


我只是针对楼主的得到的结果给出的解释,没有说64位也是这样。
64位下,一般va_arg的实现估计是至少按8字节取参数的,正好取到了 1、2、3

论坛徽章:
0
25 [报告]
发表于 2013-04-17 16:04 |只看该作者
x64上int是64位的,printft()函数指针步进也是8字节的,所以是123,x86上是102.。
safedead 发表于 2013-04-17 10:48
回复 20# hellioncu

x64 LINUX平台

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
26 [报告]
发表于 2013-04-17 16:28 |只看该作者
ilogo1 发表于 2013-04-17 16:04
x64上int是64位的,printft()函数指针步进也是8字节的,所以是123,x86上是102.。


X64的int是32位,long是64位
你的问题和ABI有关
我前面的回复很清楚的叙述了:当a、b、c是int时,压栈长度为4字节,当a、b、c为long时,压栈长度是8字节
不管压栈是按照4字节还是8字节,ABI的特性决定了:
在AMD64 SYS V调用约定下,不管是4字节还是8字节参数压栈,前4个整数参数(printf的格式字串是第一个整数参数,是个指针)
的数值,寄存器优于栈内存,不会发生高4字节低4字节组合的问题

所以pmerofc说的对,这个问题在不指定ABI时候是UB

X64 LINUX使用的ABI也是“小端字节序,栈传递参数”
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP