Page 27
3 C++ 编程规范
以下编程规范适用于本地 C++代码。
3.1 编译器选项
3.1.1 预编译头
?一定不要使用预编译头。
Visual C++ 项目默认使用预编译头文件。其原理是当生成stdafx.h/cpp文件时,巨大的Windows 头文件只被编译一次。项目中其他任何一个.CPP 文件都需要首先包含 #include \,这样项目才能正确生成。当编译器找到 \时,便知道何时插入预编译头信息。
在代码示例中,必须关闭预编译头选项。在您的项目属性中,找到C/C++ 标签页,选择 Precompiled headers 节点。点击 Not using precompiled headers 单选按钮,之后点击OK。请确保修改了所有的配置(包括Debug配置和Release配置)。之后,移除所有源文件的 #include
? 2015 Microsoft Corporation. All rights reserved. All-In-One Code Framework (http://1code.codeplex.com)
Page 28
3.1.2 开启所有警告,并当做错误来对待 ?您应该以最高警告等级来编译所有代码。
?您应该把警告当做错误来对待。
编译器提示的警告通常对于鉴别低劣的代码和隐晦的bug非常有用。您可以以编译器警告对您的代码进行额外的验证。
在Visual Studio中,您可以在项目的属性设置页面开启警告等级4。在项目属性设置页面,找到 “Configuration Properties”, “C/C++”, “General” ,将“Warning Level” 设置为 “Level 4”。
? 2015 Microsoft Corporation. All rights reserved. All-In-One Code Framework (http://1code.codeplex.com)
Page 29
3.2 文件和结构
3.2.1 stdafx.h, stdafx.cpp, targetver.h
?您应该删除Visual Studio项目模板生成的 stdafx.h, stdafx.cpp 和 targetver.h 文件以保持示例的简洁。然而,如果您有许多被大量代码文件共享的标准头文件,您可以创建单独的文件来包含它们。这非常类似于Windows.h的作用。
3.2.2 头文件
?一定请在头文件内使用包含保护符(include guards),来防止头文件被无意的多次包含。
以下示例代码中的#ifndef 和 #endif ,应该为头文件的第一行和最后一行代码。示例代码展示了如何在 “CodeExample.h”中使用 “#ifndef/#endif” 作为包含保护符。
// File header comment goes first ...
#ifndef CODE_EXAMPLE_H_ #define CODE_EXAMPLE_H_
class CodeExample { ... }; #endif
您也可以使用 “#pragma once” (微软编译器的一个特定拓展)来替代 “#ifndef/#endif” 包含保护符:
// File header comment goes first ...
#pragmaonce
class CodeExample { ... };
?您不应该在头文件内实现函数。头文件只能包含函数声明和数据结构。它们的实现应置于.cpp 文件。
? 2015 Microsoft Corporation. All rights reserved. All-In-One Code Framework (http://1code.codeplex.com)
Page 30
3.2.3 实现文件
实现文件包含了全局函数,局部函数和类方法实际的函数体。实现文件是拓展名为.c 或者 .cpp的文件。注意,实现文件不必包含整个模块的完整实现。它可以被分隔,并包含一个公共内部接口。
?您应该将不必导出的声明放置在实现文件中。此外,您应该为它们加上static关键字,以限制其作用域在该.cpp/.c 文件定义的编译单元。这将减少当链接2个或更多使用了相同内部变量的.cpp 文件时,出现“multiply-defined symbol” 错误的情况。
3.3 命名规范
3.3.1 通用命名规范
?一定请为各种类型,函数,变量,特性和数据结构选取有意义的命名。其命名应能反映其作用。
单字符变量应该仅用于计数器(i, j)或者坐标(x, y, z)。根据经验,变量作用域越大,便越应该使用描述性强的命名。
?您不应该在标识符名中使用缩短或缩略形式的词。比如,使用“GetWindow”而不是“GetWin”。对于公共类型,线程过程,窗口过程,和对话框过程函数,为“ThreadProc”, “DialogProc”, “WndProc”等使用公共后缀。
3.3.2 标识符的大小写命名规范
如下表格描述了对不同类型标识符的大小写命名规范。 标识符 类 枚举 大小写命名规范 Pascal规范 Pascal规范 命名结构 名词 名字 示例 class ComplexNumber {...}; class CodeExample {...}; class StringList {...}; enum Type {...}; ? 2015 Microsoft Corporation. All rights reserved. All-In-One Code Framework (http://1code.codeplex.com)
Page 31
函数,方法 接口 结构体 Pascal规范 PascalC规范,带‘I’ 前缀 所有字母大写,以‘_’分隔单词 所有字母大写,以‘_’分隔单词 Camel规范 Pascal规范,带‘T’ 前缀 名词或或 动名词 名字 名词 void Print() void ProcessItem() interfaceIDictionary {...}; struct FORM_STREAM_HEADER 宏, 常量 参数,变量 模板参数 #defineBEGIN_MACRO_TABLE(name) ... #defineMACRO_TABLE_ENTRY(a, b, c) ... #defineEND_MACRO_TABLE() ... constint BLACK = 3; exampleText, dwCount T, TItem, TPolicy 名词 名词 3.3.3 匈牙利命名法
?您可以对参数和变量使用匈牙利命名法。然而,匈牙利命名法相当老旧,会对代码重构造成困难。例如,当改变变量类型时,您需要对所有代码都进行更改。
如下表格定义了一套配套的匈牙利命名法标记,如果您使用匈牙利命名法,建议使用它们。 类型 bool, BOOL, bitfield BYTE WORD DWORD HRESULT VARIANT HANDLE int, unsigned int short, unsigned short 标记 f dw hr vt h 描述 一个旗标。例如, BOOL fSucceeded; 一个8位无符号数。BYTE应当仅用于不透明量,例如cookies,位字段等 一个16位无符号数。WORD应当仅用于不透明量,例如cookies,句柄,位字段等 一个32位无符号数。DWORD应当仅用于不透明量,例如cookies,句柄,位字段等 HRESULT 一般用于Win32的错误或状态值。 一个 OLE VARIANT。 一个句柄 一个32位序数(可以用于<, <=, >, >=等比较)。注意:在64 位Windows内整数为32 位。 一个16位序数。尽量不要使用这些标志,除非在磁盘格式和堆结构体中。 ? 2015 Microsoft Corporation. All rights reserved. All-In-One Code Framework (http://1code.codeplex.com)