PS:整理重定义之后,我发现最大的问题是之前没有理解预处理、编译、链接,理解编译才是最关键的地方 ~
一、头文件中声明或定义函数
- 头文件中只声明函数,一个工程下的多个c文件,可以多次包含该头文件
- 头文件中定义了函数,一个工程下的多个c文件,就只能包含一次该头文件,不同c文件包含该头文件会出现重定义
二、预处理与编译
预处理与编译:https://github.com/xuelangZF/CS_Offer/blob/master/C%2B%2B/Compiler.md
1.预处理
预处理器是在程序源文件被编译之前根据预处理指令对程序源文件进行处理,预处理器指令以#号开头标识,末尾不包含分号
C/C++提供的预处理功能主要有文件包含、宏替换、条件编译等
(1)文件包含
当使用预处理指令#include引用头文件时,相当于将头文件中所有内容,复制到include处
(2)宏替换
宏替换只作代码字符序列的替换工作,不作任何语法的检查,也不作任何的中间计算
宏定义在源文件中必须单独另起一行,换行符是宏定义的结束标志,不需要分号等符号作分隔符
续行是通过 \符号,然后再紧跟回车符号
(3)条件编译
2.编译
编译是对源文件进行编译,而不是对头文件编译,对头文件的处理在预处理时就已完成
三、重定义与编译和链接
1.出现重定义的两个条件
- 函数定义放在头文件中
- 头文件 被多个c文件包含
2.重定义是对目标文件 链接时报的错误,与编译无关,只是由于编译两次函数的定义,而导致链接时重定义
3.#pragma once
或 #ifndef...#define...#endif
,由于头文件嵌套包含,防止同一个c文件里对同一个头文件二次包含、二次编译, 但无法解决重定义
四、重定义理解的例子
情况一:函数声明与函数定义分开,不会出现重定义问题
func()函数的定义放在func.c,声明放在func.h
main.c包含 func.h、func1.h、func2.h#pragma once;
、 #ifndef...#define...#endif
解决重复包含 head.h 的问题
1 | ================c文件================ |
情况二:函数函数定义放在头文件中,该头文件只在c文件中包含一次,不会出现重定义问题
func()函数的定义放在func.h
注意:func.h 只是在 func1.c 中被包含,只被编译了一次
1 | ================c文件================ |
情况三:函数函数定义放在头文件中,该头文件在多个c文件中包含,会出现重定义问题
func()函数的定义放在func.h
注意:func.h 只是在 func1.h 中被包含,而不是 func1.c中被包含,但是 main.c 中包含了 func1.h,相当于也包含了 func.h
编译器编译的是c文件
编译main.c时由于包含 func1.h,由于 func1.h 中包含了 func.h,则编译了func()函数
编译func1.c时由于包含 func1.h,由于 func1.h 中包含了 func.h,则又编译了func()函数
编译结束后生成 main.o、func1.o,将两个目标文件链接时,由于存在两个func()函数的定义,就会报重定义的错
1 | ================c文件================ |
五、重定义与类的内联函数
类里面定义函数,就是默认内联,不会出现重定义的问题
内联函数是用代码膨胀代替函数调用,直接将函数下的代码复制在内联处,不是调用,需要找到一个函数的入口地址