【C语言进阶剖析】43、函数的声明和定义

1 声明和定义

  • 声明的意思在于告诉编译器程序单元的存在,定义则明确指示程序单元的意义
  • C 语言中通过 extern 进行程序单元的声明
  • 一些程序单元在声明时可以省略 extern

注意:在 C 语言中,当有多个源文件的时候,编译器编译文件的顺序是不确定的。所以不能编写依赖于编译顺序的代码。

2 实例分析

// 43-1.c
#include<stdio.h>
#include<malloc.h>
extern int g_var;
extern struct Test;
int main()
{
    extern void f(int i, int j);
    extern int g(int x);
    struct Test* p = NULL;
    printf("%p\n", p);
    printf("g_var = %d\n", g_var);
    f(1, 2);
    printf("g(3) = %d\n", g(3));
    free(p);
    return 0;
}
// global.c
#include<stdio.h>
int g_var = 10;
struct Test
{
    int x;
    int y;
};
void f(int i, int j)
{
    printf("i + j = %d\n", i + j);
}
int g(int x)
{
    return (int)(2 * x + g_var);
}

编译运行:

$ gcc 43-1.c global.c -o 43-1
43-1.c:5:15: warning: useless storage class specifier in empty declaration
 extern struct Test;
               ^~~~
$ ./43-1
(nil)
g_var = 10
i + j = 3
g(3) = 16

可以看到,变量 g_var,结构体 struct Test,函数 f(int i, int j) 和函数 int g(int x) 在文件 global.c 中定义,语句 extern struct Test 之前的 extern 可以去掉。

  • 问题1:将文件 global.c 中的 int g_var = 10; 改成 float g_var = 10; 重新编译运行。
gcc 43-1.c global.c -o 43-1
$ ./43-1
(nil)
g_var = 1092616192
i + j = 3
g(3) = 16

发现打印出来的 g_var 时一个很大的数字,这是为什么呢?
因为 g_var 的定义是 float 类型,float 类型在内存的存储方式与 int 类型在内存的存储方式是不一样。以float 存储的数据再以 int 方式打印,当然取出的不是我们想要的数据了。

  • 问题2:将 43-1.c 中的第 10 行的 struct Test* p = NULL; 改为:struct Test* p = (struct Test*)malloc(sizeof(struct Test)); 再次编译
$ gcc 43-1.c global.c -o 43-1
43-1.c: In function ‘main’:
43-1.c:11:50: error: invalid application of ‘sizeof’ to incomplete type ‘struct Test’
     struct Test* p = (struct Test*)malloc(sizeof(struct Test));
                                                  ^~~~~~

编译器告诉我们这时候的 sizeof 中的 struct Test 是不完整的,为什么呢?
在多个源文件一起编译,我们不能确定每个文件的编译顺序,在编译文件 43-1.c 时,使用了 sizeof(struct Test),此时编译器并不知道结构体 struct Test 是什么样子的,所以不能求解出内存大小,无法分配空间。

!!!注意:绝对不能编写依赖于编译顺序的程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值