CPP {extern声明, 头文件里的extern声明, 头文件的防重复包含的宏定义}

CPP {extern声明, 头文件里的extern声明, 头文件的防重复包含的宏定义}

extern声明

性质

#有参数默认值的函数#
void F(int, string){}, void F(int = 1, string = "A"){}, 这是错误的! (因为对于F(2,"X")此时两个函数都可以调用 就歧义了);
其实有参数默认值的函数, 他不是放在实现里的, 而是放在extern声明里的, 即extern void F(int,string); extern void F(int=1,string="A"); 然后统一写一个实现void F( int a, string b){ ...}; (即不同的有默认值的函数声明 他关心的 只是函数参数的值而已, 跟函数实现是无关的, 即他们都对应同一个函数实现);
. 注意, 此时你F()F(2) 他都会使用的是F(int=1,string="A"), 即F() == F(1,"A"), F(2) == F(2, "A");
. 所以如果你再写一个extern void F( int, string="B"); 这是错误的, 因为对于F(2) 他可以是F(2,"A") 也可以是F(2,"B") 这就歧义了, 即有默认值的函数声明 最多只有1个;

头文件的防重复包含的宏定义

定義

A.h头文件 必须要形如以下格式:
#ifndef A_H_
#define A_H_
...
#endif

extern技术 他是防止链接时的错误(即重定义错误), 而头文件的防重复包含的宏定义 这个技术 他与链接无关 他是防止编译时的错误, 主要是以下几个作用:
0(头文件相互包含的编译错误): 比如A.h里面 有#include<B.h>, 同时 B.h里面 有#include<A.h>, 此时如果A.h, B.h里 都没有使用防重复包含技术, 那么编译器就陷入死循环了(因为无限套娃了… 知道运行时死循环 还有编译时死循环 hh);
. 注意这个语法是合法的 并不是我们凭空故意瞎想出来的, 两个头文件互相包含 并不是一个语法错误, 因为只要你使用防重复包含技术 即使你让两个头文件互相包含 这并没有错; (但最好别这么弄 说明你的代码逻辑有问题 可能会存在潜在的逻辑错误) 问题在于: 你头文件里的代码逻辑是什么, 你要保证 即使两个头文件相互包含了 但是这两个头文件里的代码逻辑 一定是单向的 不可以是(两者相互调用);
. . 比如A.h: using a = b; B.h: using b = a;, 此时即使使用防重复包含技术 还是会编译出错, 因为头文件展开的次序 一定是唯一的, 比如程序最先执行进入A.h, 那么他里面有一个#include <B.h> 因此会去展开B.h (虽然B.h里也包含了A.h 但因为此时已经有#define A_H_了 不会再去展开A.h), 然后执行using b = a; 会发现 全局里并没有这个a符号, 于是报错 (undefined未定义错误);
. . 再举个更复杂的错误, 两个头文件相互包含 也使用防重复包含技术了, A.h: using a = int; B.h: using b = a;, 即使你的头文件里的代码逻辑是单向的, 但你要保证 最终头文件展开的次序头文件里代码逻辑的方向是一致的; 比如编译器先进入A.h 然后由于重复包含 编译器随后进入了B.h 此时遇到了using b = a 同样会产生未定义错误, 因此 你要保证 编译器要最先展开A.h 即有了using a = int;之后 再去展开B.h;
. 总之: 最好不要头文件相互包含, 即使相互包含 只要使用这个宏定义技术 到时候 文件展开的次序 一定是唯一的! 要么是先展开A.h 然后再展开B.h 要么是相反, 这取决于: 编译器最先遇到哪个头文件, 比如main.cpp里面是 #include<A.h> 那么编译器最先遇到A.h (但是他是后展开的) 因为A.h里面有#include<B.h> 因此会最先展开B.h, 总之 在一个.o生成文件里 他俩的展开次序是固定的 虽然相互包含了;
1(代码冗余): 比如A.cpp里面 他会有#include <A.h>, #include <B.h> 然后B.h里面 也有#include<A.h>; 这样会导致 看起来A.cpp里面 会重复多次的 #include<A.h> 也就是比如A.h里面是 extern int a;, 那么A.cpp里面 有多个extern int a;, 这虽然语法是没问题的, 但毕竟不太好 因为肯定效率会损失; 而使用防重复包含技术后 就可以解决这个问题;
. 注意这个语法是合法的 并不是我们凭空故意瞎想出来的, 而且他是常见的 你可以把头文件包含 想象成是一棵树, 那么一个节点 他会#include <所有的父节点> 那么根节点会重复包含 在实际开发中 他是经常会发生的;

性质

头文件的extern, 主要用在 链接期间(即多个.o文件) 发挥作用;
而头文件的防重复包含技术, 主要是在 编译期间(即单个.o文件) 发挥作用;

头文件里的extern声明

定义

頭文件裏的變量/函數 都必須用extern声明 不可以实现(实现必须放在.cpp文件), 否则 会导致重复定义redefinitoin错误;
他主要是在
多个.cpp文件会涉及到链接
时, 会使用这个技术; 主要是防止全局符号的重复定义;
. 比如说G.h里面有个: int D; 然后A.cpp和B.cpp都会#include<G.h>, 此时编译是不会出错的 (因为A.o, B.o没有错误), 但是将A.o, B.o链接到一起时 会出错 因为有两个全局变量int D;

  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值