关于C语言的整型和浮点型之间的强制转换与输出格式符问题

//最初的情形
#include <stdio.h>
int main()
{
int a=3;
double b=1;
b=1/a;
printf("%-15d%-15d%-15f%-15f",1/a,b,1/a,b);
}
输出结果:0 0 0.000000 0.000000

//第二次的情况
#include <stdio.h>
int main()
{
int a=3;
double b=1;
b=1/a;
printf("%-15d%-15d%-15f%-15f",1.0/a,b,1.0/a,b);
}
输出结果:1431655765 1070945621 0.000000 0.333333
请问前两个数据时怎么来的,1.0/a发生了强制转换,但b为什么会改变?另外对于输出的第三个数据,C语言在已经发生强制转换的情况下为什么不能用浮点型的格式符输出?
//第三次修改
#include <stdio.h>
int main()
{
int a=3;
double b=1;
b=1.0/a;
printf("%-15d%-15d%-15f%-15f",1/a,b,1/a,b);
}
输出结果:0 1431655765 0.000000 0.333333

第二个数据怎么来的?
//第四次修改
#include <stdio.h>
int main()
{
int a=3;
double b=1;
b=1.0/a;
printf("%-15d%-15d%-15f%-15f",1.0/a,b,1.0/a,b);
}
输出结果:1431655765 1070945621 0.333333 0.333333

这次为什么第三个数据可以正常输出了?第一、二个数据怎么来的?

1:这里涉及到函数进栈时的,不定参数转换问题,float,double类型的,进栈的时候都是按double计算的,8个字节;所以不管参数里面是%f,还是%lf都是按8个字节取的,然后强制转换为f;
//第二次的情况
int a=3;double b=1;b=1/a;
printf("%-15d%-15d%-15f%-15f",1.0/a,b,1.0/a,b);
输出结果:1431655765 1070945621 0.000000 0.333333
压进栈的是double,double,double,double(8,8,8,8);1.0/3,0.0,1.0/3,0.0
函数里面使用的是int,int,float,float(4,4,8,8)
分析:首先1.0/3所占的8个字节按照平均分4个字节并按int输出;第二个0.0按float输出;第三个1.0/3按float输出;最后0.0没用到;所以其结果等价于printf("%-15d%-15d%-15f%-15f",1.0/a,b,1.0/a); 如果不信,你可以试试printf("%-15d%-15d%-15f%-15f",1.0/a,b,b); 的结果是等价于printf("%-15d%-15d%-15f%-15f",1.0/a,b,b,1.0/3);

//第三次修改
int a=3;
double b=1;
b=1.0/a;
printf("%-15d%-15d%-15f%-15f",1/a,b,1/a,b);
输出结果:0 1431655765 0.000000 0.333333

压进栈的字节类型分别为int,double,int,double(4,8,4,8);0,1.0/3,0,1.0/3
而函数里面使用的字节分别为int,int,float,float(4,4,8,8)
很显然,在第二个位置;会取1.0/3double类型的前4个字节;然后还剩下1.0/3double的后4个字节,以及0int的4个字节,以及1.0/3的8个字节;剩下的那2个4字节一起转换为float类型,其doube结果是5.291174399002e-315,转换为float是0;1.0/3转换为float就是0.333333

//第四次修改
int a=3;
double b=1;
b=1.0/a;
printf("%-15d%-15d%-15f%-15f",1.0/a,b,1.0/a,b);
输出结果:1431655765 1070945621 0.333333 0.333333
压进栈的字节类型分别为int,double,int,double(4,8,4,8);1.0/3,1.0/3,1.0/3,1.0/3
而函数里面使用的字节分别为int,int,float,float(4,4,8,8)
按照上面的分析,必然是这种结果
其等价于 printf("%-15d%-15d%-15f%-15f",1.0/a,b,1.0/a);追问

你的意思是输出时虽然可以以不同格式输出,但并不是进行了强制转换,仅仅是按照不同数据类型的字节数来从栈中取,对吧?
我之前是受97可以用%c输出'a'误导,以为这是强制转换的一种形式,这样分析的话
printf("%c\n%c",97); //之所以会输出的一个'a'和一个空,正是由于97保存为4字节long,取出了其中的一个字节'a' 和一个字节空输出,对吧?
如果我想弄清它每个二进制位进栈和出栈的顺序,这是属于编译原理的内容吗?

追答

是的,我在windows上测试的,char是会转成int类型的,所以也是取4个字节;故在不定个数参数的函数里面,对参数的解析都要做相应转换,基本类型只能取4个字节,8个字节等,也是为了对齐吧;如果没有这些所谓的类型提升,会导致很多bug出现的对于不定个数的参数函数来说;自己可以测试一下;
函数进栈顺序是先是函数参数,然后是返回地址,然后是代码段;栈是高到低存放;

温馨提示:答案为网友推荐,仅供参考
第1个回答  2012-10-02
额,我建议你看看编译原理,那里的内容能够让你更感兴趣。scanf定义的人他们写的函数,你只要会用就行,深究下去没有必要。你要是觉得想要深究下去的话,你可以使用windows或者linux的系统接口(getc与putc,windows的没见过),自己模仿写一下,这样你更能明白原理了。写的时候要考虑缓冲与非缓冲,那些东西可能会更有意义。。。
相似回答