test.c中的代码
#include <stdio.h>
#include <stdlib.h>
int* test()
{
int *new = malloc(sizeof(int));
printf("test.c输出:%p\n",new);
return new;
}
main.c中的代码
#include <stdio.h>
int main(void)
{
int*p = test();
printf("main.c输出:%p\n",p);
}
输出结果
test.c输出:0x1005042a0
main.c输出:0x5042a0
为什么同一个地址,子函数和主函数里输出结果会不同?
a.c中的代码
#include <stdio.h>
int main(int argc,char * argv[]){
fadd(3.0f,3.0f);
return 0;
}
b.c中的代码
#include <stdio.h>
void fadd(float a,float b){
float c;
c = a+b;
printf("%f\n",c);
}
结果是6吗?上机运行后的结果竟然是2.125,这一定会让我们大吃一惊。
在最古老的 C 语言中,函数的参数列表并不是函数接口的一部分,C 编译器对旧式风格的函数甚至连实参的个数都不进行检查。下面是旧式风格的函数:
int f1(){
return 3;
}
int f2(a,b,c)
int a,b;
char c;
{
return a+b;
}
之后随着C语言的发展,对函数的参数进行了更严格的类型检查,函数的参数列表也就成了函数接口的一部分。下面的属于新式风格的函数
int f1(void){
return 3;
}
int f2(int a, int b, char c)
{
return a+b;
}
在 C 语言中,如果有一个函数未经声明就直接使用,则C编译器会把这个函数当作旧式风格的函数,并且会使用缺省类型作为函数的类型。比如例一中的test()会缺省类型为:
int test();
函数缺省类型为int,若你的函数返回值不是int,就会出现一些莫名其妙的错误。
例二与返回值无关,为什么也错了?原来C编译器对旧式风格的函数会进行一个被称为“实参提升”的动作。凡是低于 int 型的其他整型,包括 char 和 short 都会被提升为 int,而单精度 float 则会被提升为 double;其他类型保持不变。
于是,C 编译器面对未声明就使用的函数调用“fadd(3.0f,3.0f);”时,默默地进行了实参提升的操作。真正执行的函数调用是“fadd(3.0,3.0);”,压入栈的是两个 double 类型的浮点数 3.0,共占了 16 字节。在小端机器上,浮点数 3.0 的存放在低地址的 4 字节中存放 0x00000000,在高地址的 4 字节中存放 0x40080000。但在文件 b.c 中,函数 fadd 是新式风格的函数,其接口为“void fadd(float a,float b)”,按照函数声明,仍然把形参 a 和 b 当作 float 来处理,依照 C 调用约定,参数从右向左入栈,所以形参 a 对应的是 0x00000000, 形参 b 对应的是 0x40080000。
总之,远离旧式风格的 C 函数,同时记住,函数要先声明再使用,否则我们就不知不觉地在使用旧式风格的函数声明。