前言
在上一篇了解了函数的传参和一些基本用法,今天介绍一下函数怎么在编译器里用单文件或者多文件来定义和调用。
单文件
一般在写一个简单的函数或者说工程文件时,直接将函数与主函数“main”写在一个文件里,比如写一个加法函数:
#include<stdio.h>
int Add(int x, int y)
{
return x+y;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d",&a, &b);
int ret = Add(a,b);
printf("%d",ret);
return 0;
}
这个情况就是单文件情况下的使用,但在单文件里编写函数要注意一个点就是自定义的函数要写在主函数的上面,否则会出现编译器报错的情况,如图:
这是因为编译器是从第一行代码往下开始编译的,要是在编译调用函数的代码时发现上面没有定义的这个函数,编译器就会报错了。
单文件的函数调用很简单,接下来看一下多文件的情况下定义与调用。
多文件
⼀般在企业中我们写代码时候,代码可能⽐较多,不会将所有的代码都放在⼀个⽂件中;我们往往会根据程序的功能,将代码拆分放在多个⽂件中。
⼀般情况下,函数的声明、类型的声明放在头⽂件(.h)中,函数的实现是放在源⽂件(.c)⽂件中。
具体如下:
Add.c
int Add(int x,int y)
{
return x+y;
}
Add.h
int Add(int x,int y);
test.c
#include<stdio.h>
#include<Add.h>
int main()
{
int a,b;
scanf("%d %d",&a, &b);
printf("%d",Add(a,b));
return 0;
上面就是加法函数在多文件情况下的定义与调用;简单来说就是自己编写了一个库函数Add,<Add.h>文件是放的定义函数名与格式,<Add.c>文件是头文件里的函数运行的过程;就像我们使用的printf函数要在代码前面包含头文件<stdio.h>一样,Add就像是这样的库函数一样,不过一个是C语言提供的,一个是自己创建的。
static关键字
static是静态的意思:
修饰局部变量;
修饰全局变量;
修饰函数。
介绍static之前先了解一下作用域吧。
变量的作用域和生命周期
在我们编程时会用到各种各样的变量,每个变量我们用到时都会自定义一个变量名称,以便在后续编程中使用它,但每个名称的不是一直有效的,他有效的范围就跟他的作用域相关。
局部变量:作用域就在变量所在的局部范围。
局部变量的⽣命周期是:进⼊作⽤域变量创建,⽣命周期开始,出作⽤域⽣命周期结束。
#include <stdio.h>
void test()
{
int i = 0;//局部
i++;
printf("%d ", i);
}
int main()
{
int i = 0;//局部
for(i=0; i<5; i++)
{
test();
}
return 0;
}
上面这段代码段中i就是一个局部变量,他只在for语句的这段代码中有效,出了这段代码i就无法继续使用。
全局变量:作用域是整个工程。
全局变量的⽣命周期是:整个程序的⽣命周期。
例如:
int x = 10;//全局
int main()
{
........
return 0;
}
这段代码中x就是创建的全局变量,他在这个工程文件中的任何地方都可以使用。
static修饰的局部变量
#include <stdio.h>
void test()
{
int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for(i=0; i<5; i++)
{
test();
}
return 0;
}
如图局部变量仅能在他所在的局部范围内使用,出了它的作用域他就会销毁释放内存,再次访问时会重新创建,所以一直打印1。那给它加上static修饰一下会出现什么情况呢?
#include <stdio.h>
void test()
{
static int i = 0;
i++;
printf("%d ", i);
}
int main()
{
int i = 0;
for (i = 0; i < 5; i++)
{
test();
}
return 0;
}
可以看到经过static修饰后i即使在出了test函数后依然存在,并没修销毁释放内存,而是在他每次的基础上加1打印,说明static修饰的局部变量生命周期改变了。
这是因为局部变量的创建默认在内存的栈区,当static修饰过后就存到了静态区,在静态区的变量和全局变量的生命周期是一样的,但作用域不变,也就是说在使用完后不会销毁,但它只能在他本身的区域内使用。
如下代码:printf在for语句外面不能打印,但在for里面可以打印。
感兴趣的可以复制到编译器里面试试printf在for里面跟外面的区别以及n加static与不加static的区别。
#include<stdio.h>
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
static int n = 0;
n++;
}
printf("%d", n);
return 0;
}
static修饰的全局变量和函数
在这之前先说明一下extern的作用:
extern
在工程里面有两个及两个以上的.c文件时,在一个.c文件里创建了一个全局变量,在其他.c文件里使用时要用extern说明。
例如:
test.c
int g_val = 2018;
main.c
#include <stdio.h>
extern int g_val;
int main()
{
printf("%d\n", g_val);
return 0;
}
static修饰全局变量
test.c
static int g_val = 2018;//全局
main.c
#include <stdio.h>
extern int g_val;
int main()
{
printf("%d\n", g_val);
return 0;
}
在上面这段代码中我在全局变量前加上了static,在运行时会发现在编译时出现连接性错误。
结论:
⼀个全局变量被static修饰,使得这个全局变量只能在本源⽂件内使⽤,不能在其他源⽂件内使⽤。本质原因是全局变量默认是具有外部链接属性的,在外部的⽂件中想使⽤,只要适当的声明就可以使⽤;但是全局变量被 static 修饰之后,外部链接属性就变成了内部链接属性,只能在⾃⼰所在的源⽂件内部使⽤了,其他源⽂件,即使声明了,也是⽆法正常使⽤的。
static修饰的函数
在上面介绍了多文件的情况下函数条调用,那在.c文件中对函数进行static修饰会出现什么现象呢?
Add.c
static int Add(int x, int y)
{
return x+y;
}
main.c
#include <stdio.h>
extern int Add(int x, int y);
int main()
{
printf("%d\n", Add(2, 3));
return 0;
}
会发现和全局变量一样,编译时报错。
结论:
static 修饰函数和 static 修饰全局变量是⼀模⼀样的,⼀个函数在整个⼯程都可以使⽤,被static修饰后,只能在本⽂件内部使⽤,其他⽂件⽆法正常的链接使⽤了。
本质是因为函数默认是具有外部链接属性,具有外部链接属性,使得函数在整个⼯程中只要适当的声明就可以被使⽤。但是被 static 修饰后变成了内部链接属性,使得函数只能在⾃⼰所在源⽂件内部使⽤。
---------------------------------分隔符
本次对函数相关知识的介绍就结束了,以上都是小编的个人理解,有错请指正,诸君共勉。