C语言进阶-2

1、多文件C语言项目

1.1、简单的C语言程序(项目)

        只有一个C文件(a.c),编译的时候gcc a.c -o a,执行的时候./a

1.2、复杂的C语言程序(项目)

        是由多个C文件构成的。例如一个项目中包含2个c文件(a.c, b.c),编译的时候 gcc a.c b.c -o ab,执行的时候 ./ab

        在a.c和b.c中分别定义main函数,各自单独编译时没问题;但是两个文件作为一个项目来编译
gcc a.c b.c -o ab的时候,就会报错:multiple definition of `main',这是因为a.c和b.c这时候组成了一个程序,而一个程序必须有且只能有一个main函数。

1.3、为什么需要多文件项目

        因为一个真正的C语言项目是很复杂的,包含很多个函数,写在一个文件中不利于查找、组织、识别,所以人为的将复杂项目中的很多函数,分成了一个一个的功能模块,然后分开放在不同的.c文件中,于是乎有了多文件项目。

        所以,在b.c中定义的一个函数,很可能a.c中就会需要调用。你在任何一个文件中定义的任何一个函数,都有可能被其他任何一个文件中的函数来调用。但是大家最终都是被main函数调用的,有可能是直接调用,也可能是间接调用。

1.4、多文件项目中,跨文件调用函数

        在调用函数前,要先声明该被调用函数的原型。只要在调用前声明了该函数,那么调用时就好像这个函数是定义在本文件中的函数一样。

注意:函数使用的三大要素:函数定义、函数声明、函数调用

        1、如果没有定义,只有声明和调用:编译时会报连接错误。undefined reference to `func_in_a'

        2、如果没有声明,只有定义和调用:编译时一般会报警告,极少数情况下不会报警告。但是最好加上声明。

        3、如果没有调用,只有定义和声明:编译时一般会报警告(有一个函数没有使用),有时不会报警告。这时候程序执行不会出错,只是你白白的写了几个函数,而没有使用浪费掉了而已。

        4、在一个程序中,不管是一个文件内,还是该程序的多个文件内,都不能出现函数名重复的情况,一旦重复,编译器就会报错。主要是因为编译器不知道你调用该函数时到底调用的是哪个函数,编译器在调用函数时是根据函数名来识别不同的函数的。

1.5、跨文件的变量引用

        (1)在a.c中定义的全局变量,在a.c中可以使用,在b.c中不可以直接使用,编译时报错 error: ‘g_a’ undeclared (first use in this function)。

       (2) 想在b.c中使用a.c中定义的全局变量,有一个间接的使用方式。在a.c中写一个函数,然后函数中使用a.c中定义的该全局变量,然后在b.c中先声明函数,再使用函数。即可达到在b.c中间接引用a.c中变量的目的。

        (3)想在b.c中直接引用a.c中定义的全局变量g_a,则必须在b.c中引用前先声明g_a,如何声明变量? extern int g_a;

1.5.1、extern关键字

extern int g_a;   

        这句话是一个全局变量g_a的声明,这句话告诉编译器,我在外部(程序中不是本文件的另一个文件)某个地方定义了一个全局变量 int g_a,而且我现在要在这里引用它告诉你编译器一声,不用报错了。

1.5.2、注意

        1、只在b.c中声明变量,但是别的文件中根本没定义这个变量,那么编译报错(连接错误)undefined reference to...

        2、在a.c中定义了全局变量g_a,但是b.c中没有声明g_a,引用该变量会直接报错了,未定义。

        3、在a.c中定义,在b.c中声明,a.c和b.c中都没有引用该变量,程序不会出错。只是白白的定义了一个变量没用,浪费了。

        4、局部变量不能跨文件使用,为局部变量属于代码块作用域。他的作用域只有他定义的那个函数内部。

        5、静态局部变量不能跨文件使用,因为其本质上还是个局部变量。

        6、讨论跨文件使用问题,只用讨论全局变量和函数就可以了。

1.5.3、总结

        不管是函数还是变量,都有定义、声明、引用三要素。其中,定义是创造这个变量或者数,声明是向编译器交代它的原型,引用是使用这个变量或函数。所以如果没有定义只有声明和引用,编译时一定会报错。undefined reference to `xxx'

        在一个程序里面,一个函数可以定义一次,引用可以有无数次,声明可以有无数次。因为函数定义或者变量的定义实际上是创造了这个函数/变量,所以只能有一次。(多次创造同名的变量会造成变量名重复,冲突;多次创造同名的函数也会造成函数名重名冲突)。声明是告诉编译器变量/函数的原型,在每个引用了这个全局变量/函数的文件之前都要声明该变量/函数。

1.6、头文件的引入

1.6.1、为什么需要头文件

        从之前可以看到,函数的声明是很重要的。当我们在一个庞大的项目中,有很多个源文件,每一个源文件中都有很多个函数,并且需要在各个文件中相互穿插引用函数。在没有头文件时,需要使用别的.c文件中定义的函数时,都要先在本文件中先去声明该函数的原型,否则编译器要叫。所以多了的话很麻烦,而靠头文件就可以解决函数的声明问题。

1.6.2、#include包含头文件时,用<>和""的区别

        <>用来包含系统自带的头文件,系统自带指的是不是你写的,是编译器或者库函数或者操作系统提供的头文件。

        ""用来包含当前项目目录中的头文件,这些一般是我们自己写的。

1.6.3、防止重复包含头文件

#ifndef __A_H__
#define __A_H__
//
// C语言头文件中的声明
//
#endif

1.6.4、注意

        写程序时,最好不要在头文件中定义变量。因为这时该头文件被多个源文件包含时,就会出现重复定义问题。全局变量的定义就应该放在某个源文件中,然后在别的源文件中使用前是extern声明。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值