C/C++命名规则

时间:2021-04-02 22:24:20

如果只是编写一些小程序,程序只有几十或几百行,编程风格可能并不重要。然而,如果是和许多人一起进行一定规模的项目开发,或者希望过一段时间之后,还能够快速而准确地理解自己的程序,就必须养成良好的编程习惯。良好的编程风格可以增加程序代码的可读性。编程风格最能体现一个程序员的综合素质。变量的命名规范是编程风格的一项重要内容。

变量的命名规范有很多种。在Windows下开发软件,许多人采用匈牙利命名法,而在Linux环境下,并不建议使用这种方法。


1.linux命名规范

(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。

(6)尽量避免使用全局变量。全局变量在后面的章节中会介绍。

2.Yii命名规则

Yii 推荐命名变量、函数和类时使用 驼峰风格,即每个单词的首字母大写并连在一起,中间无空格。 变量名和函数名应该使它们的第一个单词全部小写,以使其区别于类名(例如:$basePathrunController(),LinkPager)。

对私有类成员变量来说,我们推荐以下划线作为其名字前缀(例如: $_actionList)。

由于在 PHP 5.3.0 之前不支持名字空间,我们推荐类要通过某种独立的方式命名,以避免和第三方类发生冲突。鉴于此, 所有的 Yii 框架类名以 "C" 作前缀。

一个针对控制器名字的特殊规则是它们必须以单词 Controller 结尾。那么控制器 ID 即类名的首字母小写并去掉单词 Controller。 例如,PageController 类的 ID 就是 page 。这个规则使应用更加安全。它还使控制器相关的URL更加简单(例如 /index.php?r=page/index 而不是 /index.php?r=PageController/index)。

3.QT命名规则

一些规则通常对所有名字都是有用的。首先,就像我之前提到的,别用缩写。甚至很明显的缩写,比如“prev”表示“previous”从长远看也是不划算的,因为用户必须记住哪些词是缩写。

如果API本身不一致,事情自然会变得很糟糕,比如, Qt3有activatePreviousWindow()和fetchPrev()。坚持“没有缩写”的规则更容易创建一致的API。

另一个重要但更加微妙的规则是,在设计类的时候,必须尽力保证子类命名空间的干净。在Qt3里,没有很好的遵守这个规则。比如,拿QToolButton来举例。如果你在Qt3里,对一个QToolButton调用name()、caption()、text()或者textLabel(),你希望做什么呢?你可以在Qt Designer里拿QToolButton试试:

  • name属性继承自QObject,表示一个对象用于除错和测试的内部名字。
  • caption属性继承自QWidget,表示窗口的标题,这个标题在视觉上对QToolButton没有任何意义,因为他们总是跟随父窗口而创建。
  • text属性继承自QButton,一般情况下是按钮上现实的文字,除非useTextLabel为真。
  • textLabel在QToolButton里声明,并且在useTextLabel为真时显示在按钮上。

由于对可读性的关注,name在Qt4里被称作objectName,caption变成了windowsTitle,而在QToolButton里不再有单独的textLabel属性。

给类命名

标识一组类而不是单独给每个类找个恰当的名字。比如,Qt4里所有模式感知项目的视图类(model-aware item view classes)都拥有-View的后缀(QListViewQTableViewQTreeView),并且对应基于项目的类都用后缀-Widget代替(QListWidgetQTableWidgetQTreeWidget)。

给枚举类型及其值命名

当声明枚举时,时刻记住,在C++(不像Java和C#)中,使用枚举值不需要类型信息。下面的例子演示了给枚举值起个太过常用的名字所引起的危害:

    namespace Qt
    {
        enum Corner { TopLeft, BottomRight, ... };
        enum CaseSensitivity { Insensitive, Sensitive };
        ...
    };

    tabWidget->setCornerWidget(widget, Qt::TopLeft);

    str.indexOf("$(QTDIR)", Qt::Insensitive);

在最后一行,Insensitive是什么意思?一个用于命名枚举值的指导思想是,在每个枚举值里,至少重复一个枚举类型名中的元素:

    namespace Qt
    {
        enum Corner { TopLeftCorner, BottomRightCorner, ... };
        enum CaseSensitivity { CaseInsensitive,
                               CaseSensitive };
        ...
    };

    tabWidget->setCornerWidget(widget, Qt::TopLeftCorner);
    str.indexOf("$(QTDIR)", Qt::CaseInsensitive);

当枚举值可以用“或”连接起来当作一个标志时,传统的做法是将“或”的结果作为一个int保存,这不是类型安全的。Qt4提供了一个模板类 QFlags<T>来实现类型安全,其中T是个枚举类型。为了方便使用,Qt为很多标志类名提供了typedef,所以你可以使用类型 Qt::Alignment代替QFlags<Qt::AlignmentFlag>。

为了方便,我们给枚举类型单数的名字(这样表示枚举值一次只能有一个标志),而“标志”则使用复数名字。比如:

    enum RectangleEdge { LeftEdge, RightEdge, ... };
    typedef QFlags<RectangleEdge> RectangleEdges;

有些情况下,“标志“类使用了单数的名字。这时,枚举类使用-Flag做后缀:

    enum AlignmentFlag { AlignLeft, AlignTop, ... };
    typedef QFlags<AlignmentFlag> Alignment;

(这里为啥不是把”标志“类用-Flag做后缀,而是把枚举值做后缀呢?感觉有点混淆……)

给函数和参数命名

给函数命名的一个规则是,名字要明确体现出这个函数是否有副作用。在Qt3,常数函数QString::simplifyWhiteSpace()违反了这个原则,因为它返回类一个QString实例,而不是像名字所提示的那样,更改了调用这个函数的实例本身。在Qt4,这个函数被重命名为QString::simplified()。

参数名是程序员的重要信息来源,虽然在使用API时,并不直接展示在代码里。由于现代IDE在程序员写代码时可以自动显示参数名(就是自动感知或者自动补全之类的功能),值得花时间给头文件里声明的参数一个合适的名字,并且在文档中也使用相同的名字。

给布尔值设置函数(Setter)、提取函数(Getter)和属性命名

给布尔属性的设置函数和提取函数一个合适的名字,总是非常痛苦的。提取函数应该叫做checked()还是isChecked()?scrollBarsEnabled()还是areScrollBarEnabled()?

在Qt4里,我们使用下列规则命名提取函数:

  • 形容类的属性使用is-前缀。比如:
    • isChecked()
    • isDown()
    • isEmpty()
    • isMovingEnable()
    另外,应用到复数名词的形容类属性没有前缀:
    • scrollBarsEnabled(),而不是areScrollBarsEnabled()
  • 动词类的属性不使用前缀,且不使用第三人称(-s):
    • acceptDrops(),而不是acceptsDrops()
    • allColumnsShowFocus()
  • 名词类的属性,通常没有前缀:
    • autoCompletion(),而不是isAutoCompletion()
    • boundaryChecking()
    有时,没有前缀就会引起误解,这种情况使用前缀is-:
    • isOpenGLAvailable(),而不是openGL()
    • isDialog(),而不是dialog()
    (通过调用dialogue()方法,正常情况下会期望返回一个QDialog*的实例。)

设置函数名字继承自提取函数名,只是移掉了所有前缀,并使用set-做前缀,比如:setDown()还有setScrollBarsEnabled()。属性的名字与提取函数相同,只是去掉了前缀。



4.匈牙利命名法 

匈牙利命名法是一种编程时的命名规范。基本原则是:变量名=属性+类型+对象描述,其中每一对象的名称都要求有明确含义,可以取对象名字全称或名字的一部分。命名要基于容易记忆容易理解的原则。保证名字的连贯性是非常重要的。 

举例来说,表单的名称为form,那么在匈牙利命名法中可以简写为frm,则当表单变量名称为Switchboard时,变量全称应该为frmSwitchboard。这样可以很容易从变量名看出Switchboard是一个表单,同样,如果此变量类型为标签,那么就应命名成lblSwitchboard。可以看出,匈牙利命名法非常便于记忆,而且使变量名非常清晰易懂,这样,增强了代码的可读性,方便各程序员之间相互交流代码。 

这种命名技术是由一位能干的Microsoft程序员查尔斯·西蒙尼(Charles Simonyi) 提出的,他出生在匈牙利。在 Microsoft 公司中和他一起工作的人被教会使用这种约定。这对他们来说一切都很正常。但对那些 Simonyi 领导的项目组之外的人来说却感到很奇特,他们认为这是死板的表达方式,甚至说带有这样奇怪的外观是因为它是用匈牙利文写的。从此这种命名方式就被叫做匈牙利命名法。 

据说这种命名法是一位叫 Charles Simonyi 的匈牙利程序员发明的,后来他在微软呆了几年,于是
这种命名法就通过微软的各种产品和文档资料向世界传播开了。现在,大部分程序员不管自己使用
什么软件进行开发,或多或少都使用了这种命名法。这种命名法的出发点是把量名变按:属性+类型 
+对象 描述的顺序组合起来,以使程序员作变量时对变量的类型和其它属性有直观的了解,下面 
是HN变量命名规范,其中也有一些是我个人的偏向: 

属性部分 
全局变量 
g_ 
常量 
c_ 
c++类成员变量 
m_ 
静态变量 
s_ 

类型部分 
指针 
p 
函数 
fn 
无效 
v 
句柄 
h 
长整型 
l 
布尔 
b 
浮点型(有时也指文件) 
f 
双字 
dw 
字符串 
sz 
短整型 
n 
双精度浮点 
d 
计数 
c(通常用cnt) 
字符 
ch(通常用c) 
整型 
i(通常用n) 
字节 
by 
字 
w 
实型 
r 
无符号 
u 

描述部分 
最大 
Max 
最小 
Min 
初始化 
Init 
临时变量 
T(或Temp) 
源对象 
Src 
目的对象 
Dest 

这里顺便写几个例子: 
hwnd : h 是类型描述,表示句柄, wnd 是变量对象描述,表示窗口,所以 hwnd 表示窗口句柄; 
pfnEatApple : pfn 是类型描述,表示指向函数的指针, EatApple 是变量对象描述,所以它表示 
指向 EatApple 函数的函数指针变量。 
g_cch : g_ 是属性描述,表示全局变量,c 和 ch 分别是计数类型和字符类型,一起表示变量类 
型,这里忽略了对象描述,所以它表示一个对字符进行计数的全局变量。 
上面就是HN命名法的一般规则。 

小结:匈牙利命名法 

匈牙利命名法 

MFC、句柄、控件及结构的命名规范 Windows类型 样本变量 MFC类 样本变量 
HWND hWnd; CWnd* pWnd; 
HDLG hDlg; CDialog* pDlg; 
HDC hDC; CDC* pDC; 
HGDIOBJ hGdiObj; CGdiObject* pGdiObj; 
HPEN hPen; CPen* pPen; 
HBRUSH hBrush; CBrush* pBrush; 
HFONT hFont; CFont* pFont; 
HBITMAP hBitmap; CBitmap* pBitmap; 
HPALETTE hPaltte; CPalette* pPalette; 
HRGN hRgn; CRgn* pRgn; 
HMENU hMenu; CMenu* pMenu; 
HWND hCtl; CState* pState; 
HWND hCtl; CButton* pButton; 
HWND hCtl; CEdit* pEdit; 
HWND hCtl; CListBox* pListBox; 
HWND hCtl; CComboBox* pComboBox; 
HWND hCtl; CScrollBar* pScrollBar; 
HSZ hszStr; CString pStr; 
POINT pt; CPoint pt; 
SIZE size; CSize size; 
RECT rect; CRect rect; 

一般前缀命名规范 前缀 类型 实例 
C 类或结构 CDocument,CPrintInfo 
m_ 成员变量 m_pDoc,m_nCustomers 

变量命名规范 前缀 类型 描述 实例 
ch char 8位字符 chGrade 
ch TCHAR 如果_UNICODE定义,则为16位字符 chName 
b BOOL 布尔值 bEnable 
n int 整型(其大小依赖于操作系统) nLength 
n UINT 无符号值(其大小依赖于操作系统) nHeight 
w WORD 16位无符号值 wPos 
l LONG 32位有符号整型 lOffset 
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函数的远指针 

前缀 符号类型 实例 范围 
IDR_ 不同类型的多个资源共享标识 IDR_MAIINFRAME 1~0x6FFF 
IDD_ 对话框资源 IDD_SPELL_CHECK 1~0x6FFF 
HIDD_ 对话框资源的Help上下文 HIDD_SPELL_CHECK 0x20001~0x26FF 
IDB_ 位图资源 IDB_COMPANY_LOGO 1~0x6FFF 
IDC_ 光标资源 IDC_PENCIL 1~0x6FFF 
IDI_ 图标资源 IDI_NOTEPAD 1~0x6FFF 
ID_ 来自菜单项或工具栏的命令 ID_TOOLS_SPELLING 0x8000~0xDFFF 
HID_ 命令Help上下文 HID_TOOLS_SPELLING 0x18000~0x1DFFF 
IDP_ 消息框提示 IDP_INVALID_PARTNO 8~0xDEEF 
HIDP_ 消息框Help上下文 HIDP_INVALID_PARTNO 0x30008~0x3DEFF 
IDS_ 串资源 IDS_COPYRIGHT 1~0x7EEF 
IDC_ 对话框内的控件 IDC_RECALC 8~0xDEEF 

Microsoft MFC宏命名规范 名称 类型 
_AFXDLL 唯一的动态连接库(Dynamic Link Library,DLL)版本 
_ALPHA 仅编译DEC Alpha处理器 
_DEBUG 包括诊断的调试版本 
_MBCS 编译多字节字符集 
_UNICODE 在一个应用程序中打开Unicode 
AFXAPI MFC提供的函数 
CALLBACK 通过指针回调的函数 

库标识符命名法 标识符 值和含义 
u ANSI(N)或Unicode(U) 
d 调试或发行:D = 调试;忽略标识符为发行。 

静态库版本命名规范 库 描述 
NAFXCWD.LIB 调试版本:MFC静态连接库 
NAFXCW.LIB 发行版本:MFC静态连接库 
UAFXCWD.LIB 调试版本:具有Unicode支持的MFC静态连接库 
UAFXCW.LIB 发行版本:具有Unicode支持的MFC静态连接库 

动态连接库命名规范 名称 类型 
_AFXDLL 唯一的动态连接库(DLL)版本 
WINAPI Windows所提供的函数 

Windows.h中新的命名规范 类型 定义描述 
WINAPI 使用在API声明中的FAR PASCAL位置,如果正在编写一个具有导出API人口点的DLL,则可以在自己的API中使用该类型 
CALLBACK 使用在应用程序回叫例程,如窗口和对话框过程中的FAR PASCAL的位置 
LPCSTR 与LPSTR相同,只是LPCSTR用于只读串指针,其定义类似(const char FAR*) 
UINT 可移植的无符号整型类型,其大小由主机环境决定(对于Windows NT和Windows 9x为32位);它是unsigned int的同义词 
LRESULT 窗口程序返回值的类型 
LPARAM 声明lParam所使用的类型,lParam是窗口程序的第四个参数 
WPARAM 声明wParam所使用的类型,wParam是窗口程序的第三个参数 
LPVOID 一般指针类型,与(void *)相同,可以用来代替LPSTR