【C++】多文件的代码规范

算是C嘎嘎入门教程(但至少需要知道HelloWorld怎么写
内容不能说全,因为是想到哪写到哪,再次就是C++是真的很杂。
(写完后博文编辑器提示我,本文章可能要20分钟读完,做好心理准备…



1、头文件(*.h)、源文件(*.cpp)

  • 头文件不参与编译,头文件的最大作用是简化/规范代码。一大段代码可以移动到“XXX.h”中,然后那大段代码的位置可以简单一个#include"XXX.h"代替。通常情况下头文件仅可包含函数声明、变量声明、类/结构体的声明或定义。
  • 源文件参与编译,无法通过编译那一般是某名称未声明/未定义(或者过定义/重复定义),一般IDE(例如VSCode)能给你指出这些语义错误。
  • 绝对不能#include"XXX.cpp",哪怕目前能跑,下一步指不定瘸给你看。迫不及待想看是怎么瘸的?跳转到4.2,但还是建议顺序阅读(毕竟文章内容我进行过调整的


2、声明与定义

  • 声明可以重复无数次,但定义只能一次(不能多也不能少),无论是变量、函数、类、结构体。
  • C++的定义具有声明效果。
  • 如果变量有初始化那么肯定是定义,不可能是声明。例如extern int num;extern int num=3;,前者是声明,后者是定义;也例如struct Item;struct Item{int num=5;};,前者是声明,后者妥妥的是定义。
  • 仅有声明而没有定义的类/结构体是无法实例化的(也就是无法创建对象),会在编译阶段出现报错。
  • 仅有声明而没有定义(或未能寻找到定义)的变量/函数,会在链接阶段出现报错。

2.1、以下表格展示声明和定义的区别:

说明 代码截图
裸奔(不带static/extern修饰)的是定义,并且会被赋予默认初值 代码截图-1.1
static修饰的变量是定义 代码截图-1.2
extern修饰的变量是声明。
但如果对变量赋初值那么为是定义(因为初始化)
代码截图-1.3
声明/创建类型:class/struct 代码截图-1.4
创建类型:typedef 代码截图-1.5
声明/创建函数 代码截图-1.6

2.2、以下表格展示仅有声明没有定义时的报错:

说明 代码截图
变量 代码截图-1.7
函数 代码截图-1.8代码截图-1.8-1代码截图-1.8-2
类/结构体 代码截图-1.9


3、staticextern

这俩修饰词可以作用于变量和函数,而对类class和结构体struct来说将不起作用的,不起效的原因说来话长,这里展开会跑题。

3.1、staticextern的作用:

作用域 extern static <无>
全局 [定义]:变量/函数可供其他cpp文件访问
[声明]:可访问其他cpp文件的变量/函数
[定义]变量/函数仅供本cpp文件使用(可有效防止污染命名空间
[声明]仅用于函数,声明一个静态函数
(等同extern)
局部 [声明]:访问全局变量/函数。实际没啥用处,但可以起一个规范作用(强调某东西是全局的 [定义]:创建静态局部变量,创建行为只会执行一次并且变量会长久滞留内存中直到程序结束 [定义]:创建局部变量,仅供本作用域使用

特别的,在类中使用static修饰的静态成员变量仅仅是起到“声明”的效果,还要对该变量进行定义。因为这是类内的,在此不展开说明。类内搞特殊的语法多了去了,全指出来可是会死人的,除了static之外还有virtualfinalexplictoperatorconstmutable等关键词。


3.2、staticextern的应用:

多cpp文件下它们的作用尤为重要:

  1. extern确保函数/全局变量定义在指定cpp文件,防止出现重复定义;
  2. static保护变量/函数不受其他cpp文件的干扰,同时也不污染全局命名空间(有效避免无意中造成的重定义);
  3. extern用的比较多的情况下是全局声明(也就是放在函数体外),放在函数体内的局部声明更像是起到一种强调作用;
  4. extern在声明/定义函数时可省略(有和没有都一个样)。

以下为样例代码和运行结果:

//T1_Main.cpp
extern int num;
extern void Func_1(int);
extern void Func_2(int);

int main() {
   
	num = 100;
	Func_1(num);
	Func_2(num);

	//extern void Func_0();//Func_0是T1_Extra-2.cpp下定义的静态函数,
	//Func_0();//取消这两行注释后IDE会提示Func_0未定义(因为静态函数不对外
	return 0;
}
//T1_Extra-1.cpp
#include<stdio.h>

int num = 10;
void Func_1(int val) {
   
	printf_s("%d,%d\n",num,val);
}
//T1_Extra-2.cpp
#include<stdio.h>

static int num = 10;
extern void Func_1(int);

static void Func_1(int val) {
   
	return;
}

void Func_2(int val) {
   
	Func_1(777);//可以看到这里并没有调用外部文件的Func_1,而是本文件下的静态函数Func_1。说明本文件下的静态函数优先级更高
	printf_s("%d,%d\n", num, val);
}

static void Func_0() {
   //本文件下的静态函数不对外,也就是其他cpp文件是没法访问到这里的函数Func_0
	printf_s("!!!\n");
}

代码截图-2.1



4、#include

4.1、用简单但离谱的代码来展示#include的作用:

//T2_Extra.h
printf_s("%d\n", 555);
//T2_Main.cpp
#include<stdio.h>
int main() {
   
#include "T2_Extra.h"
	return 0;
}

这份代码等同于:

#include<stdio.h>
int main() {
   
printf_s("%d\n", 555);
	return 0;
}

#include的作用就是简单粗暴的文本替换罢了,没什么特别的。


4.2、#include一个cpp文件的问题:

为什么我要放在这里才讲#include的作用,那是因为只有这样才能清晰地表述#include"XXX.cpp"这种行为到底有多蠢。

//T3_Main.cpp
#include<stdio.h>
#include"T3_Extra.cpp"

int main(
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值