网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
预处理功能是C语言特有的功能,它是在对源程序正式编译前由预处理程序完成的。程序员在程序
中用预处理命令来调用这些功能。
#开头的是编译预处理的指令,他们不是C语言的成分,但是C语言程序离不开他们。
指令 | 解释 |
# | 空指令 |
#include | 包含一个源代码文件 |
#define | 定义宏 |
#undef | 取消已定义的宏 |
#if | 判断条件为真,则编译下面{}内的代码 |
#ifdef | 如果宏已经定义,则编译下面{}内的代码 |
#ifndef | 如果宏没有被定义,则编译下面{}内的代码 |
#elif | 判断前面的#if的条件不为真,即#elif条件为真时,则编译下面{}内的代码 |
#endif | 结束#if······#elif······程序块 |
(PS:只是简单解释了,具体的自己去看一下)
1.3.1 函数原型
如果不给出函数原型,编译器会猜测你所调用的函数的所有参数都是int,返回类型也是int。编译器
在编译的时候只看当前的一个编译单元,它不会去看同一个项目中的其他编译单元以找出那个函数
的原型。如果你的函数并非如此,程序链接的时候不会出错。但是执行的时候就不对了。所以需要
在调用函数的地方给出函数的原型,以告诉编译器那个函数究竟长什么样。
1.3.2 头文件
把函数原型放到一个头文件(以.h结尾)中,在需要调用这个函数的源代码文件(.c文件)中#include
这个头文件,就能让编译器在编译的时候知道函数的原型。
(PS:使用尖括号和双引号的区别在于头文件的搜索路径
尖括号:编译器会到系统路径下查找头文件
双引号:编译器会先在当前目录下查找头文件,如果没有找到,再到系统路径下查找
)
同一个头文件可以被多次引入,多次引入的效果和一次引入的效果相同,因为头文件在代码层面有
防止重复引入的机制。
(头文件只能包含变量和函数的声明,不能包含定义,否则在多次引入时会引起重复定义错误。)
只有声明可以被放在头文件中
是规则不是法律
否则会造成一个项目中多个编译单元里有重名的实体.
某些编译器允许几个编译单元中存在同名的函数,或者用weak修饰符来强调这种存在。
标准头文件结构。
同一个编译单元里,同名的结构不能被重复声明。如果你的头文件里有结构的声明,很难这个头文
件不会在一个编译单元里被#include多次,所以需要“标准头文件结构”。
#ifndef __LIST__HEAD__
#define __LIST__HEAD__
#include "node.h"
typedef struct _list{
Node* head;
Node* tail;
}list;
#endif
运用条件编译和宏,保证这个都文件在一个编译器单元中只会被#include一次;
#pragma once也能起到相同的作用,但不是所有的编译器都支持。
1.4 *声明和定义*
超级重要,一定要理解。
定义:表示创建变量或分配存储单元(产生代码)
变量的声明
int i;//变量的定义
extern int i;//变量的声明
声明:说明变量的性质,但并不分配存储单元(不产生代码 )
二、错误示范及解决办法
对下列经常出现的错误解释(以分享的代码为例)
**1、**lcd1602.c(12): error C279: ‘tab’: multiple initialization //重复定义错误 下面也有另一种说法
(多个地方对这几个常量初始化了重复定义)
tips:如果在声明的时候给变量赋值,那么就和去掉extern直接定义变量赋值是等价的
int i = 0;
extern int i = 0; //在声明时对变量进行了赋值,声明不再是声明,变成定义了。
上述两者时等价的
错误举例
撤销lcd1602.h中的赋值操作
错误得到解决。
2、*** WARNING L1: UNRESOLVED EXTERNAL SYMBOL SYMBOL: TAB MODULE: .\Objects\main.obj (MAIN) *** WARNING L2: REFERENCE MADE TO UNRESOLVED EXTERNAL SYMBOL: TAB MODULE: .\Objects\main.obj (MAIN) ADDRESS: 001FH
//只做了声明,没有进行定义
错误举例
补上定义即可。(还有一种类似错误,可能是没有把C文件添加进项目中。)
3、*** ERROR L104: MULTIPLE PUBLIC DEFINITIONS SYMBOL: TAB MODULE: .\Objects\lcd1602.obj (LCD1602) *** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS SEGMENT: ?CO?LCD1602
//也是属于重复定义类
错误举例
产生原因是在lcd1602.h中对 tab[] 进行了定义
extern uchar code tab[]={‘0’,‘1’,‘2’,‘3’,‘4’,‘5’,‘6’,‘7’,‘8’,‘9’};//这是定义(上面有讲)
对于复杂的程序,有很多C文件和头文件,这个时候全局变量就必须在头文件中声明(不需要初始
化),然后在C文件中定义(该初始化的要初始化)。如果在头文件中定义,则编译的时候会出现
重复定义的错误。如果只有头文件中声明就会出现没有定义有警告。
在.c文件中定义,在.h文件中声明,就可避免此类错误的发生。
***(只有声明可以被放在头文件中,是规则不是法律。)
高概率出现的错误只有这些了吧,若还是有问题请留言,我会做出解答。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
g-0UoSY1QX-1715476135091)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新