printf函数栈的问题

jiandingzhe 2013-05-10 01:44:33
我们知道,C语言是调用者负责管理堆栈,所以实现有可变参数的函数。对于可变参数的函数,其压栈与清栈在编译时写在调用处,而其参数的使用则是被调用函数在运行时控制。那么,对于这个例子:
#include <stdio.h>

int main(int argc, char** argv)
{
double a = 1.2; // 8 bytes
float b = 3.4; // 4 bytes

printf("%f %f\n",a,b);
}

我想,它大概压栈的时候,先塞进去一个指针,再塞一个8字节的double,再塞一个4字节的float。但是当printf函数使用堆栈内容的时候,它的对后续参数的判断,应当仅仅依据我传过去的字符串模板。
那么,它是如何使用相同的两个模板(都是%f)识别不同的两个参数的(一个8字节,一个4字节)?
...全文
318 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
jiandingzhe 2013-05-24
  • 打赏
  • 举报
回复
引用 11 楼 youyou1912 的回复:
这种用法有问题, c变参调用, 被调用者是无法判断参数格式的, 要通过字符串制定. 因此%f告诉被调用者参数为4字节float, 但其实传入的是double(8字节), 这将导致被动函数判断错误.
我的问题就是:它没报错
就是那个党伟 2013-05-13
  • 打赏
  • 举报
回复
引用 1 楼 adlay 的回复:
它不能识别, float 作为参数传进去的时候会转换成 double, printf 函数还是按 double 取
++
lin5161678 2013-05-13
  • 打赏
  • 举报
回复
引用 11 楼 youyou1912 的回复:
这种用法有问题, c变参调用, 被调用者是无法判断参数格式的, 要通过字符串制定. 因此%f告诉被调用者参数为4字节float, 但其实传入的是double(8字节), 这将导致被动函数判断错误.
printf里面的 %f 都是读取sizeof(double)的
lm_whales 2013-05-13
  • 打赏
  • 举报
回复
这种做法是C调用约定的,几乎通用的方法。 其他调用约定,除了通过寄存器传递的以外,也几乎都是这样的。
lm_whales 2013-05-13
  • 打赏
  • 举报
回复
抱歉 32 位16位系统转long (或int)(其实根本就不做任何转换,4字节直接入栈,指针本来就是这样表示的) 多写了“16位”3个字。这句应改为 32 位系统转long (或int)(其实根本就不做任何转换,4字节直接入栈,指针本来就是这样表示的)
lm_whales 2013-05-13
  • 打赏
  • 举报
回复
int char short 16位系统 转成int,2字节压栈,32位系统 转成int,4字节压栈 float,double 转成double具体就是,用浮点寄存器堆栈获取,然后8字节,浮点寄存器栈顶数据压栈 指针16位系统 near 指针转成int(2字节其实根本就不做任何转换,4字节直接入栈) 或者 far指针转long (其实根本就不做任何转换,4字节直接入栈,指针本来就是这样表示的) 32 位16位系统转long (或int)(其实根本就不做任何转换,4字节直接入栈,指针本来就是这样表示的)
youyou1912 2013-05-10
  • 打赏
  • 举报
回复
这种用法有问题, c变参调用, 被调用者是无法判断参数格式的, 要通过字符串制定. 因此%f告诉被调用者参数为4字节float, 但其实传入的是double(8字节), 这将导致被动函数判断错误.
buyong 2013-05-10
  • 打赏
  • 举报
回复
隐含的类型强制转换
qq120848369 2013-05-10
  • 打赏
  • 举报
回复
任何变量都要内存对齐,另外因为不定参数的原因,float变量也会扩宽带double.
AnYidan 2013-05-10
  • 打赏
  • 举报
回复
引用 6 楼 zhao4zhong1 的回复:
printf里面的%和变量的一一对应关系 scanf里面的%和变量以及变量前加不加&的一一对应关系 是C代码中非常容易出错的地方,而且通常编译还不出错。 所以在编译源代码之前值得专门仔细检查一遍甚至多遍。 不要迷信书、考题、老师、回帖; 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实! 有人说一套做一套,你相信他说的还是相信他做的? 其实严格来说这个世界上古往今来所有人都是说一套做一套,不是吗? 不要写连自己也预测不了结果的代码!
printf里面的%和变量的一一对应关系 scanf里面的%和变量以及变量前加不加&的一一对应关系 是C代码中非常容易出错的地方,而且通常编译还不错。 所以在编译源代码之前值得专门仔细检查一遍甚至多遍。
赵4老师 2013-05-10
  • 打赏
  • 举报
回复
对学习编程者的忠告: 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步对应汇编一行! VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
赵4老师 2013-05-10
  • 打赏
  • 举报
回复
printf里面的%和变量的一一对应关系 scanf里面的%和变量以及变量前加不加&的一一对应关系 是C代码中非常容易出错的地方,而且通常编译还不出错。 所以在编译源代码之前值得专门仔细检查一遍甚至多遍。 不要迷信书、考题、老师、回帖; 要迷信CPU、编译器、调试器、运行结果。 并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。 任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实! 有人说一套做一套,你相信他说的还是相信他做的? 其实严格来说这个世界上古往今来所有人都是说一套做一套,不是吗? 不要写连自己也预测不了结果的代码!
jiaoyun007 2013-05-10
  • 打赏
  • 举报
回复
打开汇编窗口跟一遍,不就结了
izhongshaowu 2013-05-10
  • 打赏
  • 举报
回复
根据我的理解,printf("%f %f\n",a,b);语句中,printf会根据两个%f来寻找跟在后面的两个参数,而不会识别不同的两个参数,如:printf寻找a的时候,只识别它的4个字节,而不会当成8个字节来读。 以下是建栈的过程: 建栈: push b, push a, push pt,//"%f %f\n"字符串的函数指针 call @printf
折翼断JJ 2013-05-10
  • 打赏
  • 举报
回复
因为编译器在编译的时候就知道a有8个字节了。执行的时候就分配8个字节给a取的时候当然就取8个字节的。
看内存可以知道,a和b的内存是在一起的。

lin5161678 2013-05-10
  • 打赏
  • 举报
回复
不用识别 都是塞8个字节
www_adintr_com 2013-05-10
  • 打赏
  • 举报
回复
它不能识别, float 作为参数传进去的时候会转换成 double, printf 函数还是按 double 取

69,382

社区成员

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

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