coreBugZJ

此 blog 已弃。

汇编调用 C 语言 printf %f 输出浮点数 float 的问题:4字节 还是 8字节


 1 
 2 // 毕业论文做Pascal编译器,把编译生成的中间代码翻译为 nasm 汇编调用 C 语言库函数时,在输出 float 部分出现问题。
 3 
 4 
 5 // 先说明一下,我安排栈中数据 8字节对齐,不管数据实际大小,都分配 8字节,按最低字节寻址。
 6 // 当然,调用 C 语言函数时的参数栈,还是按 i386 的来。
 7 
 8 
 9 // C printf 格式化字符串
10 data.add( head + "c_format_float32 : db \'%f\', 0" );
11 data.add( head + "c_format_float64 : db \'%lf\', 0" );
12 data.add( head + "c_format_float64G: db \'%G\', 0" );
13 
14 
15 // 栈顶已经是 8字节的 ieee754 double 数据,然后
16 text.add( line + "push dword c_format_float64G" );
17 // 或 text.add( line + "push dword c_format_float64" ); 也正确
18 text.add( head + "call printf" );
19 text.add( head + "add esp, 12" );
20 // 生成可执行文件后,运行输出正确
21 
22 
23 // 栈顶已经是 4字节的 ieee754 float 数据,且不等于0(次栈顶 4字节全零),然后
24 text.add( line + "push dword c_format_float32" );
25 text.add( head + "call printf" );
26 text.add( head + "add esp, 12" );
27 // 生成可执行文件后,运行输出 0.000000
28 
29 
30 // 正确的是
31 // 栈顶已经是 4字节的 ieee754 float 数据,然后
32 // 先把4字节的float 转为 8字节的double
33 text.add( line + "fld dword [esp]" );
34 text.add( head + "fstp qword [esp]" ); // 8字节对齐,未覆盖栈中数据
35 text.add( head + "push dword c_format_float32" );
36 text.add( head + "call printf" );
37 text.add( head + "add esp, 12" );
38 // 生成可执行文件后,运行输出正确
39 
40 

结论:
 C 语言的 printf 使用 %f 来输出 float 时,实际上先把 4字节的float转化为 8字节的double,然后访问了栈上的 8字节数据。

(环境:Ubuntu12.04 32位 intel i3 nasm gcc)

posted on 2013-04-29 16:51 coreBugZJ 阅读(3141) 评论(2)  编辑 收藏 引用 所属分类: AssembleLinuxCPUGPUProgrammingLanguage

Feedback

# re: 汇编调用 C 语言 printf %f 输出浮点数 float 的问题:4字节 还是 8字节 2013-05-09 19:17 ilvu

印象里可变参数压栈是4字节对齐的。试一试char作为参数看看。  回复  更多评论   

# re: 汇编调用 C 语言 printf %f 输出浮点数 float 的问题:4字节 还是 8字节 2013-05-09 22:34 coreBugZJ

@ilvu
i386的参数原则上全都放在栈中,是4字节对齐的,char和short也是4字节对齐。  回复  更多评论   



只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理