友情链接:C/C++系列系统学习目录
各位读者你们好,本篇作为本基础专栏的第一篇,我并不打算直接开始梳理基础知识点
首先我们应该学习并且养成良好习惯的是:
C/C++语言编程规范⛳⛳⛳
文章目录
🚀前言
首先要清楚:代码阅读的次数远远多于代码编写的次数。我们所编写的代码更侧重于阅读方便而不是编写方便。
在C和C++的编程中,编写代码不只是为了实现功能而写代码,写代码是软件实现功能,也是一种可维护、易于维护的工作,而且是一种艺术。
如果一个程序员写的代码只是为了实现功能,没有注释,代码变量的命名乱七八糟,除了自己能看懂,有的人写的代码自己过了一段时间也看不懂,对于后续代码软件功能的维护,不可行。这样的代码就是垃圾代码,哪怕你当时很快实现了这一功能需求。那么也只是废码。因为不易于后续别人的维护和可移植。
🚀一、基本准备工作
⛳(一)设计工程目录结构
1、工程本身的文件、项目编译生成的中间文件放一个文件夹;
2、最终生成的目标文件单独放一个文件夹;
3、如果有工程依赖的库文件等单独放一个文件夹;
4、用户代码文件放单独一个文件夹,或者将头文件和源文件单独分开放置;
5、用户代码文件里面如果有比较重要的功能模块单独放一个文件夹,如陀螺仪,气压计,光感,音乐,灯效,图片,字库等。
6、重要的项目资料单独放一个文件夹保存,如硬件原理图,软件框架图,通信协议,复杂重要功能的说明等等。
7、必须维护一个软件版本升级记录文档,也可以在某个主要的代码文件内维护(不推荐)。
8、可以为一些代码阅读工具需要的生成文件开一个文件夹,如SourceInsight。
⛳(二)版权和版本的申明
1、基本原则:
位置:位于说明文件或者源文件头部,或者源文件和头文件都加上版本声明。
内容:版权、文件名,概要;版本号-作者-日期+代码更新信息,备注信息等等;
2、举例:
(1)简单版本申明
(2)头文件注释带上函数功能的简要说明,但如果在头文件有对外接口的函数声明,则在函数声明上进行函数功能的注释。
(3)源文件,说明此模块功能,主要函数,被其他函数调用的接口
(4)源文件和头文件都加上版本声明
STM32F10x_FWLib / stm32f10x_adc.h
/********************************************************************************
* @file stm32f10x_adc.h
* @author MCD Application Team
* @version V3.5.0
* @date 11-March-2011
* @brief This file contains all the functions prototypes for the ADC firmware
* library.
******************************************************************************
* @attention
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
******************************************************************************
*/
STM32F10x_FWLib / stm32f10x_adc.c
/********************************************************************************
* @file stm32f10x_adc.c
* @author MCD Application Team
* @version V3.5.0
* @date 11-March-2011
* @brief This file provides all the ADC firmware functions.
******************************************************************************
* @attention
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
******************************************************************************
*/
🚀二、布局和排版规则
⛳(一)头文件布局
1、头文件开头处的版权和版本声明。
2、预处理块:
#ifndef/#def/#endif 防止头文件被重复引用。
3、其他头文件
#include <filename.h> :(系统头文件)引用标准库的头文件,编译器将从标准库目录开始搜索。
#include “filename.h”: (项目头文件)引用非标准库的头文件,编译器从用户的工作目录开始搜索。
4、函数和类结构声明等
(1)宏定义等
(2)函数,头文件只存声明,不存定义。
(3)类结构声明
#ifndef GRAPHICS_H // 防止graphics.h被重复引用
#define GRAPHICS_H
#include <math.h> // 引用标准库的头文件
…
#include "myheader.h" // 引用非标准库的头文件
…
void Function1(…); // 全局函数声明
…
class Box // 类结构声明
{
…
};
#endif
5、extern规范用法:
(1)不提倡用全局变量,不用extern int value; 这类声明;
(2)必须使用时,要规范用法。不要在一个源文件中直接用extern调用另个一文件的变量。而是:在1.h头文件中声明extern int value;在2.h里面包含1.h用来调用value。
⛳(二)源文件布局
1、 定义文件开头处的版权和版本声明。
2、 对一些头文件的引用。
3、 程序的实现体。
// 版权和版本声明见前面图片示例,此处省略。
#include "graphics.h" // 引用头文件
…
// 全局函数的实现体
void Function1(…)
{
…
}
// 类成员函数的实现体
void Box::Draw(…)
{
…
}
⛳(三)排版和代码行基本规则
目的:使代码布局整齐清晰,便于阅读和理解。
1、起始代码的缩进:
函数或过程的开始、结构的定义及循环、判断等语句中的代码都要采用缩进风格, case语句下的情况处理语句也要遵从语句缩进要求。
2、缩进规则:
(1)缩进风格:程序块要采用缩进编写,缩进的空格数一般为4个。
(2)不用TAB用空格:以免用不同的编辑器阅读程序时,因 TAB 键所设置的空格数目不同而造成程序布局不整齐。
3、程序块大括号对齐:
(1)WIN和嵌入式底层:程序分界符" {"和“ }”:应该独占一行并且两者位于同一列,同时与引用他们的语句左对齐;
(2)linux:‘{’位于上一行的行末,此时‘}’与‘{’所在行的行首对齐,‘{’前至少有一个空格。
(3)循环格式
//多在linux底层和linux应用编程,单片机嵌入式未见此种用法。
for (...) {
... // program code
}
//windows一般统一用下面这个格式。。。
for (...)
{
... // program code
}
4、空行:
每个函数定义结束后,相对独立的程序块之间(逻辑密切除外)、变量说明和程序块中间之后必须加空行。
5、标志符语句独占一行:
if、 for、 do、 while、 case、 switch、 default等语句自占一行,不论语句的执行语句部分无论多少都要加括号{}。
6、长句拆分:
(1)单行单语句,一行不超过一个语句:
不允许把多个短语句写在一行中,即一行只写一条语句。
(2)语句的拆分:
代码长度最好控制在70-80个字符以内,较长的语句( >80字符)要分成多行书写。
函数或过程中的参数较长,循环、判断等语句中有较长的表达式或语句,要进行适应的划分,长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,使排版整齐,语句可读。
//【1】
report_or_not_flag = ((taskno < MAX_ACT_TASK_NUMBER)
&& (n7stat_stat_item_valid (stat_item))
&& (act_task_table[taskno].result_data != 0));
//【2】
for (i = 0, j = 0; (i < BufferKeyword[word_index].word_length)
&& (j < NewKeyword.word_length); i++, j++)
//【3】
CANx->sTxMailBox[transmit_mailbox].TDLR = (((uint32_t)TxMessage->Data[3] << 24) |
((uint32_t)TxMessage->Data[2] << 16) |
((uint32_t)TxMessage->Data[1] << 8) |
((uint32_t)TxMessage->Data[0]));
7、代码行内的空格和修饰符、括号等:
(1)关键字后留空格:C语言的32个关键字,如if/while/do/case ();
if (NewState != DISABLE)
(2)函数名后不留空格:紧跟括号( , 区别关键字.
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);
(3)紧跟:(号向后紧跟, )和,和;向前紧跟,不留空格; int a, b, c;
(4)二元操作符:前后加空格;==对等操作
(5)一元操作符:前后不加空格;如"[ ]“和” . “和”->"这类操作符前后不加空格.==关系密切的立即操作符
(6)对于表达式比较长的for语句和if语句,为了紧凑起见可以适当地去掉一些空格:
if ((a>=b) && (c<=d)) // 良好的风格
for (i=0; i<10; i++) // 良好的风格
x = a<b ? a:b; // 良好的风格
(7)修饰符紧靠变量名:不会被误认: int *x, y;
(8)注意运算符的优先级,并用括号明确表达式的操作顺序:
if ((a | b) < (c & d))
if ((a>=b) && (c<=d)) // 良好的风格
(9)特别注意:
【1】变量定义规则:
每个变量定义时同时进行初始化
每个变量定义单独占一行
对每个变量的作用进行注释
int n = 0;//表示个数
int I = 1;//循环控制变量
float fvalue = 0;//值
【2】二元运算符前后各空一格
number >= 0;
k = m + n;
【3】在模块之间要空一行,在return 语句前也要空一行。但不能有太多空行。
【4】不写复杂的语句,一行代码只做一件事情。
比如:最好将
int x=y+z,k=m+n;
写成2句,如下:
int x = y + z;
int k = m + n;
【5】if、else、elseif、for、do、while、case等语句最好单独占一行。
【6】每个语句块不管代码多少,都加上{},
例如:
if ( x >= 0)
{
k = m + n;
}
int iSum = 0;
int i = 0;
for ( i = 1; I < 20; i++)
{
iSum = iSum + i;
}
【7】长行拆分。太长的代码行最好拆分成几个短的代码行,最好不要超过一行(即80个字符)。
【8】对齐与缩进。严格采用阶梯层次组织程序代码, 各层次缩进的分格采用VC的缺省风格,即每层次缩进为4格,括号位于下一行,要求相匹配的大括号在同一列,对继行则要求再缩进4格。
🚀三、注释规则
注释规则:对程序功能、变量作用、重要的语句或语句块、重要模块的功能、函数及接口进行简明扼要的说明
目的:增加代码的可读性,帮助更好的理解程序。
(一)必要性:
在代码的功能、意图层次上注释,解释代码的目的、功能和采用的方法,提供代码外的信息,帮助理解,已经清楚的语句就不要重复注释。
说明:注释的目的是解释代码的目的、功能和采用的方法,提供代码以外的信息,帮助读者理解代码,防止没必要的重复注释信息。
(二)及时性和准确性:
边写代码边注释,改了代码也要改注释,不用的注释要删除。
(三)自注释:
通过对函数或过程、变量、结构等正确的命名以及合理地组织代码的结构。
说明:清晰准确的函数、变量等的命名,可增加代码可读性,并减少不必要的注释。
(四)注释格式和语言尽量统一:
1、格式尽量统一用/* */。
2、格式如果不能非常流利准确用英文表达,则统一用中文,不要中英文混用。
说明:注释语言不统一,影响程序易读性和外观排版,出于对维护人员的考虑,建议使用中文。
(五)注释所在位置和排版:
1、注释放在语句上方或者右方不放在下方,注释放在上方时必须和上面的代码用空行隔开。
2、避免在一行代码或表达式的中间插入注释。
3、注释应该与所描述内容进行同样缩排保持整齐,方便阅读。
(六)注释的量:
一般源程序有效注释量必须在20%以上。必须是有助于对程序的理解,准确易懂、清楚无二义性、简洁明了。
(七)注释文件:
1、如开头部分所说,基本说明性文件,.h文件、.inc文件、编译说明文件等。注释的内容类似头文件注释格式。
2、如开头部分所说,重要的源文件,注释内容除写上版权这些以外,注明模块功能,主要实现函数,对外接口函数,修改记录等等。
(八)注释函数:
一般包含 函数功能,输入参数,输出参数,返回值,备注信息,调用列表等。
(九)模块注释:
在模块前加上一行注释说明模块的功能,在程序块的结束行右方加注释标记,以表明某程序块的结束。
(十)代码主要注释内容:
1、有实际意义的常量、变量、宏:除非其自注释,不然都加上注释。
2、结构体声明(含数组、结构体、类、枚举等):其注释在上方,结构体中的域在其右方注释。
/* 点类型的定义 */
struct SPoint
{
int iX; /* 点的X位置 */
int iY; /* 点的Y位置 */
};
3、分支语句(条件、循环、switch):每一功能的注释。
4、大程序块结束:加上注释,便于阅读,如if,while,for这些语句的多层嵌套。
5、全局变量:要有比较详细的注释,包含其功能、取值范围、调用者和注释事项等。
🚀四、命名规则
标识符:程序员自己规定的具有特定含义的词,比如类名称,属性名称,变量名和函数名等。标识符由字母、数字、下划线“_”组成,关键字不能作为标识符。
标识符命名规则:见名知意,符合规范和标准。
⛳(一)基本规则
1、含义精确:标识符应该直观且易读,望文知意。要使用准确的英文字符.。
如:CurrentValue不写成NowValue
2、长度精简:“ min-length && max-information”–最精确精简的词。—长但不要太长
缩写:可用大家基本可用理解的缩写。temp=>tmp; message=>msg;
3、变量名组成:使用"名词"或者“形容词+名词”;
建议除了有具体含义外,还要能表明变量类型:
//匈牙利命名规则
int iwidth; // i表明该变量为int型,width指明是宽度
4、函数名组成:全局函数的名字应当使用“动词”或者“动词+名词”(动宾词组)。类的成员函数应当只使用“动词”,被省略掉的名词就是对象本身。
DrawBox(); // 全局函数
box->Draw(); // 类的成员函数
嵌入式中,如果是相关的模块驱动,前面加上模块名。
void BCT3286_SPI_Init(void);
5、常量:全用大写的字母,用下划线分割单词。
const int MAX = 100;
const int MAX_LENGTH = 100;
#define MAX_ARRAY 100
#define SHOW_DTDATA (WM_USER+0x101) //记得带上括号
6、特殊软件库前缀:为了防止某一软件库中的一些标识符和其它软件库中的冲突,可以为各种标识符加上能反映软件性质的前缀。例如三维图形标准OpenGL的所有库函数均以gl开头,所有常量(或宏定义)均以GL开头。
7、不要出现:
(1)仅靠大小写区分的相识标识符。
(2)相同命名的局部和全局变量。
(3)尽量避免名字中出现数字编号,如Value1,Value2等,除非逻辑上的确需要编号。
8、切合操作系统: 命名要切合操作系统与开发工具的风格
(1)widows中:
【1】变量和参数用小写字母开头的单词组合而成。(驼峰式命名法)
BOOL flag;
int drawMode;
【2】类名和函数名用大写字母开头的单词组合而成。(帕斯卡命名法)
class LeafNode; // 类名
void SetValue(int value); // 函数名
(2)stm32中:
同windows,差别在如果是底层驱动函数要加上模块名。
(3)linux应用程序和ARM9嵌入式:
函数和变量这些标识符采用全小写加下划线add_child。(下划线命名法)
【1】变量名必须意义准确。
例如有一个变量用于保存图书的数目,可以命名为number_of_book或者num_of_book。不建议使用i,因为它没有意义。也不建议使用number或book,因为意义不准确。
【2】不建议大小写混用。
如定义一个计数变量,int nCount;这在Windows中是一个很好的变量名,其中nCount的首字母n用来说明这个变量的类型是int。但在Linux下不建议大小写混合使用,一般标识符只由小写字母,数字和下划线构成。
【3】在失去意义的情况下,尽量使用较短的变量名。
例如有一个变量,用于暂时存储一个计数值,把变量命名为tmp_count显然要比this_is_a_temperary_counter好。
【4】不采用匈牙利命名法表示变量的类型。
如int nCount;n用于说明变量的类型,在Linux中不建议这样命名变量。
【5】函数名应该以动词开头。
因为函数是一组具有特定功能的语句块。比如一个函数,它用于取得外部输入的数值,则可以命名为get_input_number。
IIS_pin_init();
set_IIS_for_record();
start_IIS();
【6】尽量避免使用全局变量。
一套良好的命名规则有助于增加代码的可读性和可维护性。我们的目的是为了能使自己和他人更好地阅读我们的代码,对命名的要求不至于太过严苛,但也不可胡来,不限制一定的主观感受(如个人喜好),但最基本的要求是易懂,尽量使用英文单词而少用拼音(不会可以去查)。
总结起来,C++常用的命名法主要有以下四种:匈牙利命名法、驼峰命名法、帕斯卡命名法、下划线命名法。
⛳(二)匈牙利命名法
现在一般不用,多用在上位机语言
1、 核心思想:
在变量和函数名中加入前缀以增进人们对程序的理解。
2、主要方法:
标识符的名字以一个或者多个小写字母开头作为前缀;前缀之后的是首字母大写的一个单词或多个单词组合,该单词要指明变量的用途。
标准公式:变量名=属性+类型+对象描述,其中每一对象的名称都要求有明确含义,可以取对象名字全称或名字的一部分。
(1) 变量的命名
所有的变量名都应该以前缀+名字的形式出现。
指针变量记得加’p’。
char* strName;//以’\0’结尾的字符串,存储的数据是名字
int * pTemp;
(2)函数的命名
不需要加前缀,但是每一个单词的第一个字母都需要大写。
void ShowMessage(int ix);//显示信息。
函数采用首字母大写的方式进行拼写。常采用动宾结构,尽量做到简洁明了,禁止使用具有歧义的的词语。如:命函数名ChangeValue,我们就无法得知Value指代的是什么含义,必须以具有明确含义的词语来代替,可改为 ChangeTemperature 表示更改温度值(无需写成ChangeTemperatureValue,因为ChangeTemperature的含义已经够明确了,加上Value反而显得拖沓)。
(3)类型和常量命名:
所有的字母都必须大写
#define MAX_NUM 256 //常量
typedef unsigned char UNCHAR;//类型
(4)枚举类型(enum)中的变量
要求用枚举变量或其缩写做前缀。并且要求用大写。
enum EMDAYS{
EMDAYS_MONDAY;
EMDAYS_TUESDAY;
};
(5)对struct、union、变量的命名
类型用大写,并要加上前缀,其内部变量的命名规则与变量命名规则一致。结构体/联合体类型必须采用typedef的方式来定义,结构体类型必须以”S_”(S大写)开头,联合体类型必须以”U_”(U大写)开头。后面全部采用首字母大写的方式拼写,对于原先大写的缩写单词也要采用首字母大写的方式。
结构一般用S开头
struct SPoint
{
int iX; //点的X位置
int iY; //点的Y位置
};
联合体一般用U开头
union UPoint
{
long lX;
long lY;
}
3、常用前缀:
(1)属性前缀
前缀 | 数据类型 |
---|---|
g_ | 全局变量 |
c_ | 常量 |
m_ | C++类成员变量 |
s_ | 静态变量 |
rg_ | 寄存器变量 |
(2)类型前缀:
前缀 | 数据类型 |
---|---|
c | char 8位字符 ;cGrade |
str,s | string 字符型 ;strName |
sz | 以"\0"结束的字符串 ;szAppName |
ch | 字符 char 或 WCHAR 或 TCHAR 如果_UNICODE定义,则为16位字符 ;chName |
b,f | BOOL 布尔值 ,f 表示“flag”;bEnable |
by | 字节 BYTE (无符号字符) |
n,i | int 整型(其大小依赖于操作系统);nLength |
si | short int 短整型 ;siSequ |
n | UINT 无符号值(其大小依赖于操作系统);nHeight |
w | WORD(无符号短整型) 16位无符号值 ;wPos |
f | float 浮点型(有时也指文件) ;fRadius |
d | double 双精度型 ;dArea |
l | LONG 长整型 ;lOffset |
ld | long double 长双精度型 ;ldRate |
dw | DWORD 双字(32位无符号长整型) ;dwRange |
p | * 指针 ;pDoc |
lp | FAR* 远指针 ;lpszName |
lpsz | LPSTR 32位常量字符串指针 ;lpszName |
lpsz | LPCSTR 32位常量字符串指针 ;lpszName |
lpsz | LPCTSTR 如果_UNICODE定义,则为32位常量字符串指针 ;lpszName |
h | handle Windows对象句柄 ;hWnd |
lpfn | callback 指向CALLBACK函数的远指针 |
if | 输入文件流 ;ifDataFile |
of | 输出文件流 ;ofStuFile |
fn | 函数 |
h | 句柄 |
x,y | int,表示 x 坐标和 y 坐标 |
cx,cy | int,表示 x 或 y 的长度,c 表示“count”(计数) |
c(通常用cnt) | 计数 |
C | 类或结构 ; CDocument,CPrintInfo |
S | 结构体 ; SAddress |
r | 实型 |
u | 无符号 |
v | 无效 |
类型采用小写字母表示,用于标识变量的数据类型,如是指针类型,则在类型前加上小写的p,如是数组类型,则在类型前面加上小写的a。
(3)描述前缀
前缀 | 数据类型 |
---|---|
Max | 最大 |
Min | 最小 |
Init | 初始化 |
T(或Temp) | 临时变量 |
Src | 源对象 |
Dest | 目的对象 |
Value(或者val) | 值 |
Node | 节点 |
示例:
hwnd : h 是类型描述,表示句柄, wnd 是变量对象描述,表示窗口,所以 hwnd 表示窗口句柄;
pfnEatApple : pfn 是类型描述,表示指向函数的指针, EatApple 是变量对象描述,所以它表示指向 EatApple 函数的函数指针变量。
g_cch : g_ 是属性描述,表示全局变量,c 和 ch 分别是计数类型和字符类型,一起表示变量类型,这里忽略了对象描述,所以它表示一个对字符进行计数的全局变量。
⛳(三)驼峰命名法
驼峰命名法又被有些人称为小驼峰命名法,是为了和大驼峰命名法区分。
1、基本思想
当变量名或函数名是由一个或多个单词连结在一起,而构成的唯一识别字时,第一个单词以小写字母开始;第二个单词的首字母大写。
2、例如:
printEmployeePaychecks();
函数名使用了骆驼式命名法——函数名中的每一个逻辑断点都有一个大写字母来标记;
⛳(四)帕斯卡命名法
每一个单字的首字母都采用大写字母的命名格式,被称为“Pascal命名法”,源自于Pascal语言的命名惯例,也有人称之为“大驼峰式命名法”(Upper Camel Case)。
1、基本思想
单字之间不以空格断开或连接号(-)、底线(_)连结,第一个单字首字母采用大写字母;后续单字的首字母亦用大写字母。与骆驼命名法类似。只不过骆驼命名法是首字母小写,而帕斯卡命名法是首字母大写,
2、例如:
public void DisplayInfo();
string UserName;
相比小驼峰法,大驼峰法把第一个单词的首字母也大写了。常用于函数名,类名,属性。
⛳(五)下划线命名法
1、基本思想:
又被称为蛇形命名法,如 my_variable。常见于Linux内核,C++标准库。改命名法可读性稍好,但是会增加命名的长度和输入的难度。
2、例如:
print_employee_paychecks();
骆驼式命名法近年来越来越流行了,在许多新的函数库和Microsoft Windows这样的环境中,它使用得当相多。另一方面,下划线法是c出现后开始流行起来的,在许多旧的程序和UNIX这样的环境中,它的使用非常普遍。
⛳(六)文件名
1、基本思想:
文件标识符分为两部分,即文件名前缀和后缀。文件名前缀的最前面要使用范围限定符——模块名(文件名)缩写。采用小写字母命名文件,避免使用一些比较通俗的文件名,如:public.c 等。
头文件一般用来写模块里的一些函数的声明,实现写在源文件中,因此源文件前缀名最好与对应的头文件名字相同,如:snake.h对应的源文件 可命名为snake.c。
文件名要全部小写,用“_”分割;保持整个项目风格统一;
c文件以.c结尾,头文件以.h结尾;C++文件以.cpp结尾,头文件以.hpp结尾;cpp和hpp成对出现;
2、示例:
tcp_server.hpp
tcp_server.cpp
⛳(七)个人习惯命名总结
(1)类名:大驼峰风格
(2)类的成员函数、普通函数:小驼峰风格
(3)变量、对象名:小驼峰
(4)符号常量:全部大写,用下划线分割单词。 #define MAX_AGE 30 (一般用于宏)
(5)小驼峰的都可以用下划线方式,不过我喜欢用小驼峰
(6)请忘记“匈牙利命名法”(属性+类型+对象描述),这种方法已经很少使用
(7)在Qt类中,普通C++程序类中,静态变量前也可以加s_。如:static int s_rate;类的数据成员前面加m_。 如:private: int m_salary;
如果想用两个或更多的单词组成一个名称,通常的做法是用下划线字符将单词分开,如my_onions;或者从第二个单词开始将每个单词的第一个字母大写,如myEyeTooth(驼峰命名法)。(C程序员倾向于按C语言的方式使用下划线,而Pascal程序员喜欢采用大写方式。)这两种形式都很容易将单词区分开,如carDrip和cardRip或boat_sport和boats_port。
没有规定就遵循通常习惯。比如通常i,j,k表示循环控制变量,m,n,k通常表示整数或者数据个数。x,y,z通常表示数学中的变量或者坐标。
🚀五、宏、全局变量和其他注意
(一)宏的使用+定义规范:
1、由来:不易理解的数字和常量则用有意义的枚举或者宏来替代:
#define BUFF_SIZE 1024
input_data = (char *)malloc(BUFF_SIZE);
2、宏定义规范
(1)括号:宏定义表达,需要完整的括号。
#define GET_AREA(a,b) ((a) * (b))
(2)大括号:宏中有多条语句,应将语句放在一对大括号中。
#define INTI_RECT_VALUE( a, b ) {
a = 0;
b = 0;
}
(二)全局变量:
1、避免使用: 尽量避免使用,它占用程序空间,同时增大了模块间的耦合性,不利于软件维护。
2、规范:应明确其含义、作用、取值范围。明确全局变量与操作此变量的函数的关系,如创建、访问、修改。
(三)其他原则
1、专一:一行代码只做一件事情,如只定义一个变量,或只写一条语句。—易阅读和注释。
2、就近原则:尽可能在定义变量的同时初始化该变量。
3、数据大小端统一:通信协议中数据的大小端要和整个团队形成统一。
🚀六、函数和类
(一)函数
1、函数名:应能准确描述函数功能,一般以动词加宾语的形式;print_record
2、参数个数:不宜过多,1-3个为好;
3、返回值:清楚、明了,让调用者不易忽视错误情况。每种错误的返回值要清晰、明确,防止调用者误用;
linux中函数的返回值:正常的时候返回0,错误的时候返回-1或者小于零的错误码。
WINDOWS和stm32函数返回值:如果GetCommState()函数调用成功,则返回值大于零。若函数调用失败,则返回值为零,如果想得到进一步的错误信息,可以调用GetLastError()函数来获取。
4、输入参数:检查其有效性,如指针型参数判断是否为空,数组成员是否越界等等;
5、规模:限制在200行以内(不含空行和注释行);
6、功能专一:一个函数完成一个特定功能;
7、功能可预测:输入数据相同,能得到可预期的输出;
8、代码重用:多段代码重复做一件事,考虑将重复功能实现成一个函数;
9、独立性:减少与其他函数的联系,提高可读性、维护性和效率。避免函数本身和函数间的递归调用,递归影响可读性和系统资源如栈空间。
(二)类
类可以将数据和函数封装在一起,其中函数表示了类的行为(或称服务)。类提供关键字public、protected和private,分别用于声明哪些数据和函数是公有的、受保护的或者是私有的。
主张提倡的书写方式:将public类型的函数写在前面,而将private类型的数据写在后面,这种版式的程序员主张类的设计“以行为为中心”,重点关注的是类应该提供什么样的接口(或服务)。即首先考虑类应该提供什么样的函数。“这样做不仅让自己在设计类时思路清晰,而且方便别人阅读。因为用户最关心的是接口,谁愿意先看到一堆私有数据成员!”
class A
{
public:
void Func1(void);
void Func2(void);
private:
int i, j;
float x, y;
}
🚀七、编程规范杂烩
1、变量和零值比较
分别给出BOOL,int,float,指针变量 与“零值”比较的 if 语句(假设变量名为var)。
解答:
BOOL型变量:if(var) if(!var)
int型变量: if(var==0)
float型变量:
const float EPSINON = 0.000001;
if ((x >= - EPSINON) && (x <= EPSINON)
指针变量: if(var==NULL) if(var!=NULL)
剖析:
考查对0值判断的“内功”,BOOL型变量的0判断完全可以写成if(var==0),而int型变量也可以写成if(!var),指针变量的判断也可以写成if(!var),上述写法虽然程序都能正确运行,但是未能清晰地表达程序的意思,属于不良风格。一般的,如果想让if判断一个变量的“真”、“假”,应直接使用if(var)、if(!var),表明其为“逻辑”判断。
如果用if判断一个数值型变量(short、int、long等),应该用if(var==0),表明是与0进行“数值”上的比较;
而判断指针则适宜用if(var==NULL),这是一种很好的编程习惯和编程风格。
浮点型变量并不精确,所以不可将float变量用“==“或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。如果写成if (x == 0.0),则判为错。
参考文章:
作者:张痕: C/C++编程规范整理
作者:千瞱: C/ C++命名规则总结
作者:Leon_Chan0: C++编程(一):匈牙利命名法
若相关博主看见有侵权行为,请联系我删除,感谢大佬优秀的文章对我学习上的帮助。