最近好好写总结了(不能在偷懒了):这一次绝对认真,写总结写了三个多小时,学了一个小时左右TAT;
今天来复习一下c语言的多文件操作:
经过我这几天的摸索,我算是明白了:
先来总结几个常识便于下面的代码解读:
一般,我们初学c语言的时候都是用codeblocks在一个文件里面操作,但是在用vs开始写项目的时候一般都是多文件操作,这里就先来看一下多文件操作的小知识;
1.在写c语言预处理指令的时候一般我们都是用<>这种尖括号来包含要打开的文件;这里来了解一个新的“”引号,它打开的范围比<>要广一点,尖括号仅会在编译器包含目录中搜索文件,而引号不仅可以在编译器包含目录里面搜索文件,还可以在当前的文件目录下;
2.还有在多文件处理的时候经常可以遇见这样的问题:
错误 LNK1169 找到一个或多个多重定义的符号;
这就是说明在两个文件里面定义了多个相同标识符,这时候就要删除一个(记得举个例子),而这里还要了解编译器是如何处理代码的:编译器是单个单个文件编译的,首先进行预处理,修改源代码(修改后的源文件会直接放入编译器或者在中间文件中,所以不用担心加入预处理指令会修改当前代码),再将预处理后的源代码转化成二进制目标文件,最后将需要用到的目标文件合并成可执行文件;
可能说还是有点难以理解,所以我这不是来搬例子来了:
#include"print.h"
int main()
{
print("hello\n");
return 0;
}
在这里有一个头文件print.h,而这里面的函数print需要用到这个库里面的有关print函数声明,所以,在编译器初步处理之后,就相当于变成了这样:
void print(const char* s);
int main()
{
print("hello\n");
return 0;
}
这里刚开始我有疑问,这里只有函数的声明,没有函数的具体定义啊;那是由于有我还有另外一个文件:(按照这三张图片打代码可以得出结果,学编程就是要多打代码)
也就是说,为了实现这段代码,我用了三个文件:|main.c | paint.c | print.h | ,所以在编译器处理之后就差不多变成了这样:
但是这不是我们平时打的代码,我只是说是编译器会把它转化成这样便于他进一步理解,但这也是它理解的一小步;
其实对于我刚刚那样我还有些小疑问的,为什么不可以直接去掉那个声明,因为这个函数的定义本来就在主函数的前面,那时我已经试过了,是错的,我当时是这样写的:
(当然,把所有这些都写在一个文件里面就不会有这么多问题出现,这里只是在学习c语言的多文件处理)
这是为什么呢?其实根据上面处理预指令的方法,可以想象上面的的代码被编译器初步转化成这样:
可以看见在编译器将这些文件链接之后 有两个print函数的重复定义,这时候还有一个问题就是当编译器将几个文件链接的时候,一般都是把需要的函数定义或声明放过来,一般位置没有什么要求,放进来就行(学完下一个改改);
解决:让编译器正确识别标识符
//可以换成函数声明,也就是我最开始放三个图片里的
把声明包含在在一个文件里,不要被编译后缀名叫.h;也就是上面的三张图片的那个就是改进后的
然后再思考一下还有一个问题,就是如果不引用那个print.c的头文件是不是就不会发生这样的事了;
试试呗:
由于刚写完前面就不小心把刚刚代码删了,然后又懒了,所以就只想搞一个凑数了,但是效果是一样的,我把代码搞成这样,然后运行,显示未定义标识符,这是怎么回事,后来我总结为:只有当引用的文件里面有声明的时候,才会有需求,这是才会把另外文件的有关函数读取,
对了,之前有点好奇还了解了一下关于这个文件命名的事,我发现文件其实可以用中文命名,还有那个定义函数和和它有关的头文件也可以不是相关的名字,可以随便命,(但是后面的后缀别乱改,还有我说的随便只是在创建文件的时候,如果已经创建完了,还想再修改会很麻烦的,反正我现在都还没弄明白,)之所以一样是为了便于找到和理解;(我发现命名变量和函数也是最好按照好理解的命名,不要想着偷懒去命名a,b,c这种,代码短一点还好说,写项目的时候几百行代码的来,真的很容易混,那时候编译器有时候又不会报错,到时候就因为这么一个小错误去一段一段重新检查真的太不值得了,所以养成好习惯);
然后就来点不一样的:
来搞一个人员输入和打印函数:
(之所以选择不用代码段,只是想显示上面的代码文件不同)
这里的三个代码是正确的,但是在这个代码这里会发现一点不一样的,为什么这个结构体定义的时候可以重复定义在不一样的文件里面还没有报错,反正我了解的理由是里面的注释:也就是这个结构体定义作用域在函数之外,所以可以;
但是这里我是这么理解,就像上面的编译器运行分析,这里大致可以理解了,之所以要定义两个一样的结构体是我们一般没有用预指令调用的文件,编译器都是按照主函数在的文件的需求来按需调用函数的,结构体定义不可以放进去,也就是说,如果我没有在那个引用的头文件里面用那个结构体定义的话,就会报错,而在那个人员表的文件的话如果没有结构体定义里面函数就相当于用了没定义的类型,那个结构体定义只服务于那个文件,并不能被连接到主函数。(看起来很麻烦,后面可以记一下那个模板,就显得简单了)
今天的知识量有点大,下面还有一点关于这个重复定义代码的改进和文件守卫过几天再来总结QAQ~~;
哔~温馨提示,这些知识点都是基于知道如何使用vs和创建有关文件,反正我是先学完这些来的:)
今天又快要结束了哦,你学了什么呢?
“夏天好像总是热烈和明亮 。天空晴朗 ,月亮皎洁 。所以请你也要万事顺意。 在这个盛夏奔赴更好的地方 ”