c语言多个.c文件编译以及操作 |
您所在的位置:网站首页 › 虚拟机怎么导出c语言文件 › c语言多个.c文件编译以及操作 |
一、引入
在上一章中 我们在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只是为了让编译器知道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 #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 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |