编码规范汇总【持续更新】

article/2025/10/14 18:28:34

目录

  • 前言
  • 规范标准
    • C++规范
    • C#规范
  • 规范记录
    • 命名
    • 硬编码
    • 单例类【线程安全】
    • Qt定义类【隐式内存共享】

前言

作为软件工程师,出产物就应该具备工程的健壮性美观性。因此代码规范是作为软件工程师的职业素养。但总所周知,程序员的工作基本就是在维护一座屎山,这确实是现实中种种客观条件约束下导致的。
记录本篇博客,也是希望本人在打码过程,能够保持负责任的初心,以及追求完美的极客精神吧。
诸君共勉。愿人间没有ugly的代码。

规范标准

首先列出一些常见的编码规范。

C++规范

一.	变量声明与命名风格
(1)	代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。但也常以双下划綫标识类内部变量。
反例:_name / __name / $name / name_ / name$ / name__
(2)	代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。 说明:正确的英文拼写和语法可以让阅读者易于理解,避免歧义。注意,即使纯拼音命名方式 也要避免采用。 
正例:alibaba / taobao / youku / hangzhou 等国际通用的名称,可视同英文。 
反例:DaZhePromotion [打折] / getPingfenByName() [评分] / int 某变量 = 33)	变量名和函数名以小写字母开头,开头之后的部分每个单词以大写字母开头。
正例:short counter; / char itemDelimiter = ' ';4)	类名以大写字母开头。
正例:XmlService / User 
(5)	常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。 正例:MAX_STOCK_COUNT
(6)	抽象类命名使用 Abstract 或 Base 开头;异常类命名使用 Exception 结尾;测试类 命名以它要测试的类的名称开始,以 Test 结尾。
(7)	避免短的或无意义的命名。使用尽量完整的单词 组合来表达其意。
正例::AtomicReferenceFieldUpdater。
反例:变量 int a 的随意命名方式。
(8)	枚举成员名称需要全大写,单词间用下划线隔开。
(9)	单个字符的变量名只适用于用来计数的临时变量,因为此时该变量的用途十分明显
(10)	声明每一个变量都要用独立的一行
正例:int height; / int width;11)	当一个变量被用到时再声明它。
(12)	对于指针或引用,在类型名和*&之间用一个空格,但是在*&和变量名之间没有空格
正例:char *x; / const QString &myString; / const char * const y = "hello";13)	Qt的ui相关的,在ui里的变量也尽量要进行命名,特别是在代码中使用到的,反例:ui->frame,命名时注意添加该界面的标识性字段,尽量使得ui里所有变量名字在整个程序域中不重名,便于在QSS中控制。
正例:如在SE_ReportDialog.ui中的命名,m_reportFrame;在SE_CalculateWindow.ui中的命名:m_calculateFrame等。
(14)	如上个例子,在特定地方声明的变量应添加适当的前缀,如类的成员变量添加m_前缀;全局变量添加g_;局部变量添加l_。
(15)	接上一点,在前缀下划线后第一个字母,常为变量类型的缩写,如int为i,double为d。
正例:int m_iMonth; double l_dMoney;二.代码格式
(1)	大括号的使用约定。如果是大括号内为空,则简洁地写成{}即可,不需要换行;如果 是非空代码块统一如下例:
if ( ... )
{
...
}
else
{
...
}2)	左小括号和字符之间不出现空格;同样,右小括号和字符之间也不出现空格
反例:if (空格 a == b 空格)3if/for/while/switch/do 等保留字与括号之间都必须加空格。
正例:if (foo)4)	任何二目、三目运算符的左右两边都需要加一个空格。
正例:lineF == lineN 
(5)	注释的双斜线与注释内容之间有且仅有一个空格。
正例: // 这是示例注释,请注意在双斜线之后有一个空格6)	方法参数在定义和传入时,多个参数逗号后边必须加空格。即逗号左边没有空格,逗号右边有一个空格。
正例:  QT_REQUIRE_VERSION(argc, argv, "4.0.2")7)	左引号的左边和右引号的右边都有一个空格,左引号的右边和右引号的左边都没有空格。如果右引号右边是右括号的话,它们之间没有空格。
正例: qDebug() << Q_FUNC_INFO << "was called with value1:" << value1 << "value2:" << value2; 
QT_REQUIRE_VERSION(argc, argv, "4.0.2")8)	不同逻辑、不同语义、不同业务的代码之间插入一个空行分隔开来以提升可读性。 
(9)	当条件语句的执行部分多于一句的时候才使用花括号。然而在if-else语句块中,如果ifelse中的一个包含了多行,另一个为了对称性原则,也要用花括号。
正例:if (address.isEmpty()) return false;10)	每行代码不多于100个字符,超出需要换行。换行时:第二行相对第一行缩进 4 个空格,从第三行开始,不再继续缩进。运算符与下文一起换行。方法调用的点符号与下文一起换行。方法调用中的多个参数需要换行时,在逗号后进行。
正例:if (longExpression + otherLongExpression + otherOtherLongExpression) { }
三.类相关
(1)避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成 本,直接用类名来访问即可。
(2)构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在 init 方法中。
(3)类内方法定义的顺序依次是:公有方法->公有槽->信号->保护方法->私有方法->私有槽。
(4)当一个类有多个构造方法,或者多个同名方法,这些方法应该按顺序放置在一起, 便于阅读。
(5)成员变量一般为名词。函数成员一般为动词/动词+名词,当返回值为Bool型变量时,函数名一般以前缀’is’开头。正例:void setDirty(bool b);  / bool isDirty() const;6)每一个对象,只要它不是基础类型(int, float, bool, enum, or pointers),都应该以常量引用的形式传递。这条使得代码运行得更快。正例:QString myMethod(const QString &foo, const QPixmap &bar, int number);7)为了使构造函数被错误使用的可能性降到最小,每一个构造函数(除了拷贝构函数)都应该检查自己是否需要加上explicit 符号。
(8)尽量减少在头文件中包含其他头文件的数量,可以用前置声明法。正例:class KBar; 
class KFoo : public KFooBase 
{};9)假如你有一个Foo类,有Foo.h文件和Foo.cpp文件,在你的Foo.cpp文件中,要先包含Foo.h文件再包含其他头文件。正例:// .h文件 
class Foo 
{};// .cpp文件 
#include "foo.h"
#include "bar.h"
四.	控制相关
(1case标签和switch在同一列。每一个case语句的末尾都要有一个break语句或return语句。在一个 switch 块内,都必须包含一个 default 语句并且 放在最后,即使空代码。
(2)	除常用方法(如 getXxx/isXxx)等外,不要在条件判断中执行其它复杂的语句,将 复杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性
五.	注释相关
(1)	方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释 使用/* */注释,注意与代码对齐。2)	对于注释的要求:第一、能够准确反应设计思想和代码逻辑;第二、能够描述业务含 义,使别的程序员能够迅速了解到代码背后的信息。完全没有注释的大段代码对于阅读者形同 天书,注释是给自己看的,即使隔很长时间,也能清晰理解当时的思路;注释也是给继任者看 的,使其能够快速接替自己的工作。
(3)	好的命名、代码结构是自解释的,注释力求精简准确、表达到位。避免出现注释的 一个极端:过多过滥的注释,代码的逻辑一旦修改,修改注释是相当大的负担。
(4)	建议每个文件、每个类、每个函数,尤其是接口API部分,使用doxygen语法标注。

C#规范

1.	代码规范
Unity中的C#代码,变量命名和函数命名均采用小驼峰命名法,即名称首字母小写,其余单词的首字母大写。(由于Unity内置接口以及C#的系统接口都是使用大驼峰命名法(即首字母也是大写),我们使用不同命名规则就能轻易辨认出某个函数是内置的还是我们定义的)类名和常量命名使用大驼峰命名法。
Python代码,变量命名使用下划线命名法,常量命名使用大写的下划线命名法,静态变量使用大驼峰命名法,函数使用小驼峰命名法,类使用大驼峰命名法。(由于Python的变量声明不需要任何关键字,只能使用多种命名法加以区分)
其他地方的命名规则均使用大驼峰(包括Unity编辑器中的对象命名、文件命名等)
.	注释要求
每个类、函数前都要写注释,在Python中直接在类/函数前一行使用“#”来注释。在C#中使用以下格式的注释:
/// <summary>
/// 函数解释
/// </summary>
类中的成员变量也需要注释,可以使用上面的格式,也可以直接在变量后用“//”注释,如果变量作用清晰,变量名能表达清楚则可以不写注释。如果需要声明多个成员变量,可以写在一起,然后在第一个成员变量前面使用上述注释方法进行分区,如以下代码所示:
注:VS中,在声明的类、函数或者变量前输入“///”就会自动补全以上格式的注释。
另外,在定义了很多函数的情况下,要将功能相似的函数放在一起,并使用以下语句进行代码分区:
#region 区域名
.... 代码段 ....
#endregion
这样可以在编辑器中收起一部分代码段,方便查看其他部分的代码,也能作为一个注释告诉其他人这段代码是做什么的。效果如下:
最后,在代码逻辑中,也需要尽量写注释,特别是用到了其他技术(比如Unity提供的一些接口)时要注明一下。

标注示例1
标注示例2

规范记录

命名

命名除了必须符合编码规范外,同时应尽量使其让其具备良好的可读性。关于命名(实在想不到应该叫啥,或者单词都不会翻译 ),可参考CodeLf。

硬编码

在代码中,我们经常会碰到硬编码,比如存取一个本地文件的名字(如:Setting.file),比如预设的一些组件的名字(如:控件1、控件2)等等。硬编码其实无法避免,举个极端的说法,在UI上每个按钮的名字都是硬编码,这个叫做“设置”,那个叫做“关闭”。
但硬编码还是存在很大的问题,以上述读取一个文件的名字为例,如果代码中有多个地方访问该文件,直接使用硬编码时,每个地方都将使用一次"Setting.file",这是让人担忧的事情!因为当这个"Setting.file"发生变更时,我们将不得不修改每一处硬编码的地方。(当然了,我们也是可以通过全局crtl+F轻松替换)。
那为什么不采取一个更加漂亮的处理方式呢?个人建议,所有硬编码的地方,只要有第二处引用到同一个硬编码,则应该将该硬编码提取成一个常量变量储存,每个地方引用该变量
举例:

/*test.h*/
class ST_Scen_Instance
{
public:
// 这里就有个违反规范的地方是没有全大写,主要是全大写个人觉得阅读起来比较困难static const QString LatitudeName;static const QString LongitudeName;static const QString HeightName;inline void changeLLA(double latitude, double longitude, double height);inline double longitude() const;inline double latitude() const;inline double height() const;
};void ST_Scen_Instance::changeLLA(double latitude, double longitude, double height)
{for (auto &para : m_lParameterValue)if (para.m_sName == QString(LongitudeName))para.m_sInitialValue = QString::number(longitude);else if (para.m_sName == QString(LatitudeName))para.m_sInitialValue = QString::number(latitude);else if (para.m_sName == QString(HeightName))para.m_sInitialValue = QString::number(height);
}inline double ST_Scen_Instance::longitude() const
{for (auto &para : qAsConst(m_lParameterValue))if (para.m_sName == QString(LongitudeName))return para.m_sInitialValue.toDouble();return 116;
}inline double ST_Scen_Instance::latitude() const
{for (auto &para : qAsConst(m_lParameterValue))if (para.m_sName == QString(LatitudeName))return para.m_sInitialValue.toDouble();return 40;
}inline double ST_Scen_Instance::height() const
{for (auto &para : qAsConst(m_lParameterValue))if (para.m_sName == QString(HeightName))return para.m_sInitialValue.toDouble();return 0;
}
/*test.cpp*/
const QString ST_Scen_Instance::LatitudeName = "m_Latitude";
const QString ST_Scen_Instance::LongitudeName = "m_Longitude";
const QString ST_Scen_Instance::HeightName = "m_Altitude";

单例类【线程安全】

单例类可谓非常常用,但使用时容易忘记多线程访问的问题。参考:C++ 线程安全的单例模式总结。
建议使用最简单的写法为:

///  内部静态变量的懒汉实现  //
class Single
{public:// 获取单实例对象static Single &GetInstance();// 打印实例地址void Print();private:// 禁止外部构造Single();// 禁止外部析构~Single();// 禁止外部复制构造Single(const Single &signal);// 禁止外部赋值操作const Single &operator=(const Single &signal);
};Single &Single::GetInstance()
{// 局部静态特性的方式实现单实例static Single signal;return signal;
}void Single::Print()
{std::cout << "我的实例内存地址是:" << this << std::endl;
}Single::Single()
{std::cout << "构造函数" << std::endl;
}Single::~Single()
{std::cout << "析构函数" << std::endl;
}
///  内部静态变量的懒汉实现  //

Qt定义类【隐式内存共享】

由于Qt内建的一套隐式内存共享策略,即新对象引用共享数据只单纯让引用数+1,而不需要拷贝数据(这样使用值传递和const &传递效果基本一样了),只有在写时才会发生深拷贝操作。参考:Implicit Sharing。
隐式操作在绝大多数时候只会发生在后台,与程序员无关,但在少数情况下,这将会带来一定影响,甚至是致命影响。
首先是官方提到的案例,迭代器

QVector<int> a, b;
a.resize(100000); // make a big vector filled with 0.QVector<int>::iterator i = a.begin();
// WRONG way of using the iterator i:
b = a;
/*Now we should be careful with iterator i since it will point to shared dataIf we do *i = 4 then we would change the shared instance (both vectors)The behavior differs from STL containers. Avoid doing such things in Qt.
*/a[0] = 5;
/*Container a is now detached from the shared data,and even though i was an iterator from the container a, it now works as an iterator in b.Here the situation is that (*i) == 0.
*/b.clear(); // Now the iterator i is completely invalid.int j = *i; // Undefined behavior!
/*The data from b (which i pointed to) is gone.This would be well-defined with STL containers (and (*i) == 5),but with QVector this is likely to crash.
*/

然后同样是迭代的问题,详见官方API:

   QString s = ...;for (QChar ch : s) // detaches 's' (performs a deep-copy if 's' was shared)process(ch);for (QChar ch : qAsConst(s)) // ok, no detach attemptprocess(ch);

这将导致我们常规的for语句出现一个warning:
在这里插入图片描述
因此必要时采用qAsConst


http://chatgpt.dhexx.cn/article/B6XFoXKd.shtml

相关文章

51单片机串口波特率

SCON SCON 0X50工作方式1 波特率需要使用定时器1 波特率 ((2^SMOD)/32) * (定时器溢出率) 定时器溢出率 系统时钟/指令周期/装载数 SMOD 1 &#xff0c;波特率加倍 TH1 TL1 -(FOSC / INSTRU_CYCLE / 32 / BAUD); //Set auto-reload vaule TR1 1;

关于51单片机串口1发送完整的数据包

关于51单片机串口1发送完整的数据包 在参考这样的协议的条件下我们想发送一套完整的数据包该如何发送呢&#xff1f;可以设计这样的程序。 1. 串行口1接收特定包头数据包函数。 参数: Uart_Rec_Data&#xff1a;串口接收到的数据 &#xff1b; USER_Get_DataPacket: 数据存储目…

51单片机串口收发

#include<reg52.h>#define uint unsigned int #define uchar unsigned char/*本代码实现串口的收发功能&#xff0c;PC发送什么单片机就接收什么&#xff0c; 然后单片机又把接收的发出去&#xff0c;本次编写了在发送单个字符串 函数上添加了字符串函数&#xff0c;方便…

学习51单片机串口工作方式及应用

1.串口控制寄存器SCON SM2:多机通信控制位 REN:允许接收控制位 TB8:发送第九位数据 RB8:接收第九位数据 TI:发送中断标志位 RI:接收中断标志位 2.电源控制寄存器PCON 当SMOD位为1&#xff0c;则串行口方式1、方式2、方式3的波特率加倍。 3.串口的工作方式 &#xff08;1…

关于51单片机串口通信的相关知识(寄存器)

一、51单片机串口概念 1、51单片机的串行口 51单片机的串行口是一个可编程全双工的通信接口&#xff0c;具有UART&#xff08;通用异步收发器&#xff09;的全部功能。 2、51单片机的硬件连接 简单双向串口通信有两根数据通信线&#xff1a; 发送端TXD&#xff08;Transmit Da…

C51单片机串口点亮一个led

C51单片机串口点亮一个led 因为最近要用到51的串口做一些通信&#xff0c;这里写一个点led的程序记录一下。 说是一个led&#xff0c;其实可以随意多个。 主要使用到的东西&#xff1a; STC89C52芯片&#xff0c;USB转TTL下载器&#xff0c;led灯若干&#xff0c;面包板&am…

51单片机 串口

串口说白了&#xff0c;就是初始化后&#xff0c;用中断接收发送字符而已。 TXD 是 80C51 单片机的P3.1口&#xff0c;RXD 是80C51 单片机的 P3.0口 T1 溢出率 是定时器1的溢出率 &#xff0c;SMOD是发送速率倍频的16分频&#xff0c;T1每溢出一次发送一位&#xff0c;每次发送…

【记录】一次51单片机串口乱码问题排查

【记录】一次51单片机串口乱码问题排查 项目场景问题描述原因分析解决方案结语 项目场景 在51串口收发仿真实验中使用两个单片机互相通信&#xff0c;程序设定A上电1s后通过串口以16进制给B发送AA,直到B收到AA后回复BB&#xff0c;当A机确认收到AA后开始发送数据&#xff0c;若…

## 51单片机串口通讯

1&#xff0c;接线方式&#xff1a; RXD: 数据输入引脚&#xff1b;对应stc89的P3.0口&#xff1b; TXD&#xff1a;数据的发送端口;对应P3.1口&#xff1b; 注意&#xff1a;单片机的的串口TX&#xff0c;RX与外设交叉接线&#xff1b; 2串口编程要素 输出/输入数据缓冲器S…

51单片机串口通信详解

文章目录 前言一、计算机通信简介二、串口通信简介1、简介2、同步通信和异步通信2.1 同步通信2.2 异步通信 3、串行通信的传输方式4、串口通信硬件电路5、常见接口介绍 三、串口相关寄存器详解1、特殊功能寄存器SCON2、PCON寄存器3、TMOD寄存器&#xff08;定时器工作方式寄存器…

51单片机串口接收处理

目的: 通过51单片机串口外设功能&#xff0c;来对一组数据进行处理&#xff0c;新手刚刚入门可能会将串口接收到的一个数据直接赋值给一个变量&#xff0c;然后用这个变量做相应功能&#xff0c;可是这样写的不稳定性太高了&#xff0c;有可能会接收不到你要的那个数据&#…

51单片机串口通信原理

计算机串行通信基础 通信有串行通信和并行通信两种方式 串行通信&#xff1a; 将数据字节分为一位一位的形式在一条数据线上逐个传送。如下图所示 串行通信特点&#xff1a;传输线少&#xff0c;长距离传送时成本低&#xff0c;且可以利用电话网等现成设备&#xff0c;但数据的…

51单片机串口点灯

#include "reg52.h" #include "intrins.h" sfr AUXR 0x8e; sbit D5 P3^7; //定义led 接在P3.7void UartInit(void) //9600bps11.0592MHz {SCON 0x50; //配置串口工作方式1&#xff0c;RE使能接收数据 0101 0000PCON 0x00; TMOD &0x0F;TMOD |0x2…

51单片机串口使用

文章目录 前言一、串口概念二、中断中的RI、TI和SUBF1.RI2.TI3.SUBF 三、串口波特率的计算四、代码的编写总结 前言 今天将为大家讲解51单片机的串口原理及代码编写。 一、串口概念 51单片机串口是一种通信接口&#xff0c;它可以将51单片机与外部设备连接起来&#xff0c;实…

51单片机串口通信

串口通信 1、通信的基本概念2、 51单片机串口介绍2.1、串口通信简介2.2、串口内部结构2.3、串口通信寄存器SCONPCON 2.4、串口工作方式 3、串口使用方法3.1、硬件3.2、通信协议RS2323.3、串口初始化 4、硬件设计5、 软件设计6、拓展 串口的通信&#xff0c;一般是检测通信模块是…

UART串口通信

什么是串行通信? 将数据字节分成一位一位的形式在一条传输线上逐位地发送。 优点:成本低,控制复杂。 什么是异步通信? 异步通信是指通信的发送与接收设备使用各自的时钟控制数据的发送和接收过程。为使双方的收发协调,要求发送和接收设备的时钟尽可能一致。 异步通信的两…

MCU-51:单片机串口详解

目录 一、计算机通信简介二、串口通信简介2.1 同步通信2.2 异步通信 三、串行通信的传输方式四、串口通信硬件电路五、常见接口介绍六、串口相关寄存器详解6.1 特殊功能寄存器SCON6.2 PCON寄存器6.3 TMOD寄存器 七、代码演示-单片机和电脑通信7.1 串口向电脑发送数据7.2 电脑通…

51单片机学习入门(三):串口

1.串口是什么&#xff1f; 串口是一种应用十分广泛的通讯接口&#xff0c;串口成本低、容易使用、通信线路简单&#xff0c;可实现两个设备的互相通信。单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信。 51单片机内部自带UART&#xff08;…

51单片机——串口通信(发送和接受数据)

目录 一、实现的功能 二、串口通信 2.1单片机发送数据 2.1.1串口初始化 2.1.2串口发送程序 2.1.3发送效果 ​2.2单片机接收数据 2.2.1串口初始化 2.2.2接收数据程序 2.2.3接收效果 一、实现的功能 通过串口&#xff08;UART&#xff09;让单片机与计算机进行通信。51单…

51单片机-串口通信

目录 1.什么是通信 1.1.通信的概念 1.2.传送方式 1.3.同步方式 1.4.传送方向 1.5.校验方式 2.单片机串口介绍 2.1.硬件电路 2.2.电平标准 2.3.常见接口 2.4.内部结构 2.5.相关寄存器 2.6.工作模式&#xff08;模式1&#xff09; 2.7.如何配置串口中断 3.实际应用…