c语言多个.c文件编译以及操作

目录

多个.c文件

一、why?

二、如何将多个.c组合成一个?

三、示例

头文件

一、引入

二、需要一个媒介——头文件,才能知道函数到底要什么,又返回什么

三、关于#include

四、include的两种形式<> 还是""

五、#include的误区

声明

一、问题,我们在max.c里面声明的一个全局变量gAll怎么让main.c也知道有这个全局变量呢?

二、关于重复声明

下一篇:c语言格式化的输入输出 


多个.c文件

一、why?

main()里的代码太长了适合分成几个函数

一个源码文件太长了适合分成几个文件

两个独立的源代码文件不能编译形成可执行的程序

 

二、如何将多个.c组合成一个?

需要使用编译器新建项目,然后把源代码放进去,编译器会把项目中所有的源代码编译后,链接起来

编译器有编译和构建,编译指对单个源码进行编译,后者是对整个项目做链接

 

编译单元:一个.c是一个编译单元,编译器每次编译只能处理一个编译单元

 

三、示例

两个文件

max.c的内容

int max(int a,int b)

{

 return a>b?a:b;

}

main.c的内容

#include <stdio.h>

int max(int a,int b);

int main(int argc,char const *argv[]){

    int a=5;

    int b=6;

    printf("%d\n",max(a,b));

}

结果

 

头文件

一、引入

在上一章中

我们在main.c中留下了max函数的声明

在调用的时候,编译器知道我们对max函数的调用是正确的

但我们把声明去掉后?

虽然有红色提示但是还是能编译

还有结果

这是因为c语言古老的传统,会猜测max的参数全是int

假如我们把max.c的int类型改为double还能成功吗?

double max(double a,double b)

{

 return a>b?a:b;

}

但是编译又过了,但是里面肯定有问题

结果:

在mian.c和max.c都编译完成后

main中调用max.c的时候会链接max.c,可是传进去的东西错了,传出来的也错了

 

二、需要一个媒介——头文件,才能知道函数到底要什么,又返回什么

把函数原型放到一个头文件以.h结尾,在需要调用这个函数的源码文件.c中#include这个头文件,就能让编译器在编译的时候知道函数的原型

 

会发现这里就报错了,因为需要的是double类型传入的是int

将max函数改为int类型后运行正常

当然将%d改为%f,max函数类型是double也没问题

 

三、关于#include

#include是一个编译处理指令,和宏一样,在编译之前就处理了

它把那个文件的全部文本内容原封不动地插入到它所在的地方

所以也不是一定要在.c文件的最前面#include

 

现在我们用gcc看编译过程

gcc main.c max.h

使用gcc编译链接

执行成功

现在只编译main.c   gcc --save-temps main.c -c

查看main.i tail -n 50 main.i

所以include就是把max.c整个放了进来,注意这里的#是注释

 

四、include的两种形式<> 还是""

""要求编译器首先在当前目录(.c文件所在的目录)寻找这个文件,如果没有,到编译器指定的目录去找

<>让编译器只在指定的目录去找

编译器自己知道自己的标准库的头文件在哪里

linux和unix的库在这里

windows的在各种编译器下面的include里面

环境变量和编译器命令行参数也可以指定寻找头文件的目录

小结:一般来说自己写的用"",系统的用<>

 

看看stdio.h里面有什么?开始是版权声明,后面就是各种东西的定义

 

五、#include的误区

#include不是用来引入库的,做的只有一件事把这个文件原封不动的放进来

stdio.h里面只有printf的原型,printf的代码在另外的地方,某个.lib(Windows下)或.a(Unix)中

现在c语言的编译器默认会引入所有的标准库,当然用不到的会拿掉

#include<stdio.h>只是为了让编译器知道printf函数的原型,保证你调用时给出的参数值是正确的类型

 

所以说头文件:

在使用和定义(检查你对外宣称的和实际的函数的定义是不是一不一致)这个函数的地方都应该#include这个头文件

一般的做法就是任何.c都有对应的同名.h,把所有对外公开的函数的原型和全局变量(全局变量可以在多个.c中共享)的声明都放进去

那么要是有个函数不希望别人用?

在函数前面叫上static就使得它成为只能在所在的编译单元中被使用的函数

在全局变量前面加上static就使得它成为只能在编译单元(这个.c)中被使用的全局变量

 

较为推荐的头文件使用方式:

这里的max.c是max函数的原型,max.h是声明

 

 

 

声明

一、问题,我们在max.c里面声明的一个全局变量gAll怎么让main.c也知道有这个全局变量呢?

在max.h中声明

int max(int a, int b);

extern int gAll;

这样做后,我们告诉编译器在整个项目的某个地方有个叫gAll的东西

就可以在main函数中这么做了

 printf("%d\n",max(a,gAll));

结果:

但是没有这条声明编译就会报错

 

int I;是变量的定义

extern int i;是变量的声明,当然不能赋值,定义是定义声明是声明,不能搞混

声明是不产生代码的东西(就是只是默默的记下来)

函数原型

变量声明

结构声明

宏声明

枚举声明

类型声明

inline函数

而定义是产生代码的东西(函数、全局变量)

 

一个规则:只有声明可以被放在头文件中

是规则不是法律

否则会造成一个项目中多个编译单元有重名的实体

某些编译器允许几个编译单元中存在同名的函数,或者用weak修饰符来强调这种存在

 

二、关于重复声明

同一个编译单元里,同名的结构不能被重复声明

如果你的头文件里有结构的声明,很难这个头文件不会在一个编译单元里被#include多次

所以需要“标准头文件结构”

例如:

struct Node

{

    int value;

    char* name;

};

struct Node

{

    int value;

    char* name;

};

int main(int argc,char const *argv[]){

在一个main中定义两个同名的Node结构就会导致编译报错

当然我们把这个结构放入max.h中只用include就能用这个结构了

这时我们有另一个.h文件

也include了max.h,这是很常见的事情,可能有某个结构什么的要用到

我们同时也在main.c里面include了main.h

就相当于将max.h插入到main.c里面两遍,就产生了前面的问题,重复定义了两次Node

当程序结构很复杂的时候很难避免这样的事情

 

所以我们这么做

在max.h里面加入橙色的部分

#ifndef _MAX_H_  //判断该文件内有没有定义过这个宏

#define _MAX_H_  //若没有则定义

int max(int a, int b);

extern int gAll;

struct Node

{

    int value;

    char* name;

};

#endif // !_MAX_H_   结束  如果已经定义过这个宏就不会放入绿色部分的代码

注意:这种宏的定义的名字最好要加_ _保证和要用到的宏不重名

用这个机制,保证只引入过一次max.h

现在编译就对了

#include <stdio.h>

#include"max.h"

#include"main.h"

int main(int argc,char const *argv[]){

    int a=5;

    int b=6;

    printf("%d\n",max(a,gAll));

    return 0;

}

 

#pragma once 也能起到同样的作用,但是不是所有编译器都支持,例如gcc

  • 40
    点赞
  • 182
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: a. 一个c语言文件(.c文件)必须包含main函数 是正确的。因为main函数是C语言程序的入口函数,没有它程序无法执行。 b. 一个c语言文件(.c文件)可以包含两个以上main函数 是错误的。每个程序只能有一个入口函数main。 c. c语言文件(.h文件)和源文件(.c文件)都可以进行编译 是正确的。头文件和源文件都需要编译成目标文件才能链接成可执行程序。 d. 在一个可以正确执行的c语言程序中,一个c语言函数的声明(原型)可以出现任意多次 是正确的。函数的声明可以在多个文件中出现,只要它们的函数名和参数列表相同即可。 ### 回答2: a. 一个C语言文件(.c文件)必须包含main函数是正确的。main函数是C程序的入口点,编译器编译时需要找到这个函数来生成可执行文件。 b. 一个C语言文件(.c文件)不可以包含两个以上的main函数。只能有一个main函数作为程序的入口,如果有多个main函数会导致编译出错。 c. C语言文件(.h文件)和源文件(.c文件)都可以编译是正确的。头文件和源文件都可以编译成目标文件,它们一般都是被链接器连接成最终的可执行文件。 d. 在一个可以正确执行的C语言程序中,一个C语言函数的声明(原型)可以出现任意多次是正确的。函数声明只是告诉编译器函数的名称、参数和返回值等信息,在函数定义之前声明多次是可以的,但是如果函数定义和声明信息不匹配就会导致编译出错。 ### 回答3: 答案:只有选项a和c是正确的。 a. 首先,一个C语言文件(.c文件)中通常包含一个main函数,它是程序入口。如果没有main函数,编译器将无法识别程序的入口点,也就无法正确执行程序。 b. 一个C语言文件(.c文件)不应该包含两个以上的main函数。因为只有一个main函数可以作为程序入口,而且在同一个程序中,有多个入口会造成混乱。如果确实需要多个入口,则可以将main函数定义在不同的源文件中,并在编译时链接起来。 c. C语言文件(.h文件)和源文件(.c文件)都可以进行编译。头文件通常包含函数声明、类型定义、常量定义等信息。它们不包含实际的代码,因此可以被多个文件共享。在编译时,头文件将被包含在每个引用它的源文件中,然后一起编译成目标文件。 d. 在一个可以正确执行的C语言程序中,一个C语言函数的声明(原型)只能出现一次。函数原型告诉编译器函数的返回值类型、参数类型和数量,以便在调用该函数时进行参数类型检查和类型转换。如果一个函数原型出现多次,编译器将无法确定哪个是真正的原型,从而导致编译错误。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值