最新一键自助建站程序源码,网站推广与优化哪里好,qq网页版在线直接登录,济南网站建设公司推荐C语言编程规范及命名规则 编码规范总原则#xff1a;清晰、简洁、一致头文件函数标识符命名与定义变量宏、常量表达式注释排版与格式代码编辑编译其他设置 命名规则类型命名#xff1a; 其他编译器配色 参考 编码规范
总原则#xff1a;清晰、简洁、一致 清晰第一 清晰性是… C语言编程规范及命名规则 编码规范总原则清晰、简洁、一致头文件函数标识符命名与定义变量宏、常量表达式注释排版与格式代码编辑编译其他设置 命名规则类型命名 其他编译器配色 参考 编码规范
总原则清晰、简洁、一致 清晰第一 清晰性是易于维护、易于重构的程序必需具备的特征。代码首先是给人读的好的代码应当可以像文章一样发声朗诵出来。 目前软件维护期成本占整个生命周期成本的40%~90%。根据业界经验维护期变更代码的成本小型系统是开发期的5倍大型系统100万行代码以上可以达到100倍。业界的调查指出开发组平均大约一半的人力用于弥补过去的错误而不是添加新的功能来帮助公司提高竞争力。 一般情况下代码的可阅读性高于性能只有确定性能是瓶颈时才应该主动优化。 简洁为美 简洁就是易于理解并且易于实现。代码越长越难以看懂也就越容易在修改时引入错误。写的代码越多意味着出错的地方越多也就意味着代码的可靠性越低。因此我们提倡大家通过编写简洁明了的代码来提升代码可靠性。 废弃的代码(没有被调用的函数和全局变量)要及时清除重复代码应该尽可能提炼成函数。 选择合适的风格与代码原有风格保持一致 产品所有人共同分享同一种风格所带来的好处远远超出为了统一而付出的代价。在公司已有编码规范的指导下审慎地编排代码以使代码尽可能清晰是一项非常重要的技能。如果重构/ / 修改其他风格的代码时比较明智的做法是根据现有代码的现有风格继续编写代码或者使用格式转换工具进行转换成公司内部风格。
头文件
对于C语言来说头文件的设计体现了大部分的系统设计。不合理的头文件布局是编译时间过长的根因不合理的头文件实际上反映了不合理的设计。 头文件中适合放置接口的声明不适合放置实现 头文件是模块Module或单元Unit的对外接口。头文件中应放置对外部的声明如对外提供的函数声明、宏定义、类型定义等。 内部使用的函数相当于类的私有方法声明不应放在头文件中。内部使用的宏、枚举、结构定义不应放入头文件中。变量定义不应放在头文件中应放在.c文件中。变量的声明尽量不要放在头文件中亦即尽量不要使用全局变量作为接口。变量是模块或单元的内部实现细节不应通过在头文件中声明的方式直接暴露给外部应通过函数接口的方式进行对外暴露。即使必须使用全局变量也只应当在.c中定义全局变量在.h中仅声明变量为全局的。 头文件应当职责单一切忌依赖复杂 头文件过于复杂依赖过于复杂是导致编译时间过长的主要原因。很多现有代码中头文件过大职责过多再加上循环依赖的问题可能导致为了在.c中使用一个宏而包含十几个头文件。 错误示例某平台定义WORD类型的头文件 #include VXWORKS.H
#include KERNELLIB.H
#include SEMLIB.H
#include INTLIB.H
#include TASKLIB.H
#include MSGQLIB.H
#include STDARG.H
#include FIOLIB.H
#include STDIO.H
#include STDLIB.H
#include CTYPE.H
#include STRING.H
#include ERRNOLIB.H
#include TIMERS.H
#include MEMLIB.H
#include TIME.H
#include WDLIB.H
#include SYSLIB.H
#include TASKHOOKLIB.H
#include REBOOTLIB.H
…
typedef unsigned short WORD;
…这个头文件不但定义了基本数据类型WORD还包含了stdio.h syslib.h等等不常用的头文件。如果工程中有10000个源文件而其中100个源文件使用了stdio.h的printf由于上述头文件的职责过于庞大而WORD又是每一个文件必须包含的从而导致stdio.h/syslib.h等可能被不必要的展开了9900次大大增加了工程的编译时间。 头文件应向稳定的方向包含 头文件的包含关系是一种依赖一般来说应当让不稳定的模块依赖稳定的模块从而当不稳定的模块发生变化时不会影响编译稳定的模块。 就我们的产品来说依赖的方向应该是产品依赖于平台平台依赖于标准库。 若平台代码中已经包含了产品的头文件导致平台无法单独编译、发布和测试是一个非常糟糕的反例。除了不稳定的模块依赖于稳定的模块外更好的方式是两个模块共同依赖于接口这样任何一个模块的内部实现更改都不需要重新编译另外一个模块。在这里我们假设接口本身是最稳定的。 每一个 .c 文件应有一个同名 .h 文件用于声明需要对外公开的接口 如果一个.c文件不需要对外公布任何接口则其就不应当存在除非它是程序的入口如main函数所在的文件。 现有某些产品中习惯一个.c文件对应两个头文件一个用于存放对外公开的接口一个用于存放内部需要用到的定义、声明等以控制.c文件的代码行数。编者不提倡这种风格。这种风格的根源在于源文件过大应首先考虑拆分.c文件使之不至于太大。另外一旦把私有定义、声明放到独立的头文件中就无法从技术上避免别人include之难以保证这些定义最后真的只是私有的。 禁止头文件循环依赖 头文件循环依赖指a.h包含b.hb.h包含c.hc.h包含a.h之类导致任何一个头文件修改都导致所有包含了a.h/b.h/c.h的代码全部重新编译一遍。而如果是单向依赖如a.h包含b.hb.h包含c.h而c.h不包含任何头文件则修改a.h不会导致包含了b.h/c.h的源代码重新编译。 .c/.h文件禁止包含用不到的头文件 很多系统中头文件包含关系复杂开发人员为了省事起见可能不会去一一钻研直接包含一切想到的头文件甚至有些产品干脆发布了一个god.h其中包含了所有头文件然后发布给各个项目组使用这种只图一时省事的做法导致整个系统的编译时间进一步恶化并对后来人的维护造成了巨大的麻烦。 头文件应当自包含 简单的说自包含就是任意一个头文件均可独立编译。如果一个文件包含某个头文件还要包含另外一个头文件才能工作的话就会增加交流障碍给这个头文件的用户增添不必要的负担。 示例如果a.h不是自包含的需要包含b.h才能编译会带来的危害每个使用a.h头文件的.c文件为了让引入的a.h的内容编译通过都要包含额外的头文件b.h。额外的头文件b.h必须在a.h之前进行包含这在包含顺序上产生了依赖。 注意该规则需要与“.c/.h文件禁止包含用不到的头文件”规则一起使用不能为了让a.h自包含而在a.h中包含不必要的头文件。a.h要刚刚可以自包含不能在a.h中多包含任何满足自包含之外的其他头文件。 总是编写内部 #include 保护符 #define 保护 多次包含一个头文件可以通过认真的设计来避免。如果不能做到这一点就需要采取阻止头文件内容被包含多于一次的机制。通常的手段是为每个文件配置一个宏当头文件第一次被包含时就定义这个宏并在头文件被再次包含时使用它以排除文件内容。所有头文件都应当使用#define 防止头文件被多重包含命名格式为FILENAME_H为了保证唯一性更好的命名是 PROJECTNAME_PATH_FILENAME_H。 注没有在宏最前面加上单下划线_是因为一般以单下划线_和双下划线__开头的标识符为ANSIC等使用在有些静态检查工具中若全局可见的标识符以_开头会给出告警。 定义包含保护符时应该遵守如下规则 保护符使用唯一名称不要在受保护部分的前后放置代码或者注释。 正确示例假定VOS工程的timer模块的timer.h其目录为VOS/include/timer/timer.h,应按如下方式保护 #ifndef VOS_INCLUDE_TIMER_TIMER_H
#define VOS_INCLUDE_TIMER_TIMER_H
...
#endif也可以使用如下简单方式保护: #ifndef TIMER_H
#define TIMER_H
...
#endif例外情况头文件的版权声明部分以及头文件的整体注释部分如阐述此头文件的开发背景、使用注意事项等可以放在保护符(#ifndef XX_H)前面。 禁止在头文件中定义变量 在头文件中定义变量将会由于头文件被其他.c文件包含而导致变量重复定义。 只能通过包含头文件的方式使用其他 .c 提供的接口禁止在.c 中通过 extern 的方式使用外部函数接口、变量。 若a.c使用了b.c定义的foo()函数则应当在b.h中声明extern int foo(int input)并在a.c中通过#include b.h来使用foo。禁止通过在a.c中直接写extern int foo(int input);来使用foo后面这种写法容易在foo改变时可能导致声明和定义不一致。 禁止在 extern “C” 中包含头文件 在extern C中包含头文件会导致extern C嵌套Visual Studio对extern C嵌套层次有限制嵌套层次太多会编译错误。在extern C中包含头文件可能会导致被包含头文件的原有意图遭到破坏。 错误示例 extern “C”
{
#include “xxx.h”
...
}正确示例 #include “xxx.h”
extern “C”
{
...
} 一个模块通常包含多个.c 文件建议放在同一个目录下目录名即为模块名。为方便外部使用者建议每一个模块提供一个.h 文件名为目录名。 需要注意的是这个.h并不是简单的包含所有内部的.h它是为了模块使用者的方便对外整体提供的模块接口。以Google test简称GTest为例GTest作为一个整体对外提供C单元测试框架其1.5版本的gtest工程下有6个源文件和12个头文件。但是它对外只提供一个gtest.h只要包含gtest.h即可使用GTest提供的所有对外提供的功能使用者不必关系GTest内部各个文件的关系即使以后GTest的内部实现改变了比如把一个源文件c拆成两个源文件使用者也不必关心甚至如果对外功能不变连重新编译都不需要。对于有些模块其内部功能相对松散可能并不一定需要提供这个.h而是直接提供各个子模块或者.c的头文件。 比如产品普遍使用的VOS作为一个大模块其内部有很多子模块他们之间的关系相对比较松散就不适合提供一个vos.h。而VOS的子模块如Memory仅作举例说明与实际情况可能有所出入其内部实现高度内聚虽然其内部实现可能有多个.c和.h但是对外只需要提供一个Memory.h声明接口。 如果一个模块包含多个子模块则建议每一个子模块提供一个对外的 .h文件名为子模块名 降低接口使用者的编写难度 头文件不要使用非习惯用法的扩展名如 .inc 目前很多产品中使用了.inc作为头文件扩展名这不符合c语言的习惯用法。在使用.inc作为头文件扩展名的产品习惯上用于标识此头文件为私有头文件。但是从产品的实际代码来看这一条并没有被遵守一个.inc文件被多个.c包含比比皆是。 除此之外使用.inc还导致source insight、Visual stduio等IDE工具无法识别其为头文件导致很多功能不可用如“跳转到变量定义处”。虽然可以通过配置强迫IDE识别.inc为头文件但是有些软件无法配置如Visual Assist只能识别.h而无法通过配置识别.inc。 同一产品统一包含头文件排列方式 常见的包含头文件排列方式功能块排序、文件名升序、稳定度排序。 正确示例1以升序方式排列头文件可以避免头文件被重复包含 #include a.h
#include b.h
#include c/d.h
#include c/e.h
#include f.h正确示例2以稳定度排序建议将不稳定的头文件放在前面如把产品的头文件放在平台的头文件前面 #include product.h
#include platform.h相对来说product.h修改的较为频繁如果有错误不必编译platform.h就可以发现product.h的错误可以部分减少编译时间。 推荐头文件包含顺序首先是.c文件相应的.h文件其他按照稳定度排列C标准库系统.h本项目其他.h。
函数
函数设计的精髓编写整洁函数同时把代码有效组织起来。避免代码重复增加可重用性分层降低复杂度隐藏模块实现细节更模块化有利于程序的阅读维护。
整洁函数要求代码简单直接、不隐藏设计者的意图、用干净利落的抽象和直截了当的控制语句将函数有机组织起来。
代码的有效组织包括逻辑层组织和物理层组织两个方面。逻辑层主要是把不同功能的函数通过某种联系组织起来主要关注模块间的接口也就是模块的架构。物理层无论使用什么样的目录或者名字空间等需要把函数用一种标准的方法组织起来。例如设计良好的目录结构、函数名字、文件组织等这样可以方便查找。 一个函数仅完成一件功能 一个函数实现多个功能给开发、使用、维护都带来很大的困难。 将没有关联或者关联很弱的语句放到同一函数中会导致函数职责不明确难以理解难以测试和改动。 重复代码应该尽可能提炼成函数 重复代码提炼成函数可以带来维护成本的降低。 重复代码是我司不良代码最典型的特征之一。在“代码能用就不改”的指导原则之下大量的烟囱式设计及其实现充斥着各产品代码之中。新需求增加带来的代码拷贝和修改随着时间的迁移产品中堆砌着许多类似或者重复的代码。 项目组应当使用代码重复度检查工具在持续集成环境中持续检查代码重复度指标变化趋势并对新增重复代码及时重构。当一段代码重复两次时即应考虑消除重复当代码重复超过三次时应当立刻着手消除重复。 避免函数过长新增函数不超过 50 行 非空非注释行 过长的函数往往意味着函数功能不单一过于复杂。 函数的有效代码行数即NBNC非空非注释行应当在[150]区间。 例外某些实现算法的函数由于算法的聚合性与功能的全面性可能会超过50行。 延伸阅读材料业界普遍认为一个函数的代码行不要超过一个屏幕避免来回翻页影响阅读一般的代码度量工具建议都对此进行检查例如Logiscope的函数度量“Number of Statement” 函数中的可执行语句数建议不超过20行QA C建议一个函数中的所有行数包括注释和空白行不超过50行。 避免函数的代码块嵌套过深新增函数的代码块嵌套不超过4层 函数的代码块嵌套深度指的是函数中的代码控制块例如if、for、while、switch等之间互相包含的深度。每级嵌套都会增加阅读代码时的脑力消耗因为需要在脑子里维护一个“栈”比如进入条件语句、进入循环„„。应该做进一步的功能分解从而避免使代码的阅读者一次记住太多的上下文。优秀代码参考值[1, 4]。 错误示例代码嵌套深度为5层 void serial (void)
{if (!Received){TmoCount 0;switch (Buff){case AISGFLG:if ((TiBuff.Count 3) ((TiBuff.Buff[0] 0xff) || (TiBuf.Buff[0] CurPa.ADDR))){Flg7E false;Received true;}else{TiBuff.Count 0;Flg7D false;Flg7E true;}break;default:break;}}
}可重入函数应避免使用共享变量若需要使用则应通过互斥手段关中断、信号量对其加以保护 可重入函数是指可能被多个任务并发调用的函数。在多任务操作系统中函数具有可重入性是多个任务可以共用此函数的必要条件。共享变量指的全局变量和static变量。编写C语言的可重入函数时不应使用static局部变量否则必须经过特殊处理才能使函数具有可重入性。 示例函数square_exam返回g_exam平方值。那么如下函数不具有可重入性。 int g_exam;
unsigned int example( int para )
{unsigned int temp;g_exam para; // **temp square_exam ( );return temp;
}此函数若被多个线程调用的话其结果可能是未知的因为当**语句刚执行完后另外一个使用本函数的线程可能正好被激活那么当新激活的线程执行到此函数时将使g_exam赋于另一个不同的para值所以当控制重新回到“temp square_exam ( )”后计算出的temp很可能不是预想中的结果。此函数应如下改进。 int g_exam;
unsigned int example( int para )
{unsigned int temp;[申请信号量操作] // 若申请不到“信号量”说明另外的进程正处于g_exam para; //给g_exam赋值并计算其平方过程中即正在使用此temp square_exam( ); // 信号本进程必须等待其释放信号后才可继[释放信号量操作] // 续执行。其它线程必须等待本线程释放信号量后// 才能再使用本信号。return temp;
}对参数的合法性检查由调用者负责还是由接口函数负责应在项目组/模块内应统一规定。缺省由调用者负责。 对于模块间接口函数的参数的合法性检查这一问题往往有两个极端现象即要么是调用者和被调用者对参数均不作合法性检查结果就遗漏了合法性检查这一必要的处理过程造成问题隐患要么就是调用者和被调用者均对参数进行合法性检查这种情况虽不会造成问题但产生了冗余代码降低了效率。 对函数的错误返回码要全面处理 一个函数标准库中的函数/第三方库函数/用户定义的函数能够提供一些指示错误发生的方法。这可以通过使用错误标记、特殊的返回数据或者其他手段不管什么时候函数提供了这样的机制调用程序应该在函数返回时立刻检查错误指示。 设计高扇入合理扇出小于7的函数 扇出是指一个函数直接调用控制其它函数的数目而扇入是指有多少上级函数调用它。 扇出过大表明函数过分复杂需要控制和协调过多的下级函数而扇出过小例如总是1表明函数的调用层次可能过多这样不利于程序阅读和函数结构的分析并且程序运行时会对系统资源如堆栈空间等造成压力。通常函数比较合理的扇出调度函数除外通常是3~5。 扇出太大一般是由于缺乏中间层次可适当增加中间层次的函数。扇出太小可把下级函数进一步分解多个函数或合并到上级函数中。当然分解或合并函数时不能改变要实现的功能也不能违背函数间的独立性。扇入越大表明使用此函数的上级函数越多这样的函数使用效率高但不能违背函数间的独立性而单纯地追求高扇入。公共模块中的函数及底层函数应该有较高的扇入。 较良好的软件结构通常是顶层函数的扇出较高中层函数的扇出较少而底层函数则扇入到公共模块中。 废弃代码没有被调用的函数和变量) ) 要及时清除 程序中的废弃代码不仅占用额外的空间而且还常常影响程序的功能与性能很可能给程序的测试、维护等造成不必要的麻烦。 函数不变参数使用const尤其是指针类型参数 不变的值更易于理解/跟踪和分析把const作为默认选项在编译时会对其进行检查使代码更牢固/更安全。 函数应避免使用全局变量、静态局部变量和 I/O 操作不可避免的地方应集中使用 带有内部“存储器”的函数的功能可能是不可预测的因为它的输出可能取决于内部存储器如某标记的状态。这样的函数既不易于理解又不利于测试和维护。在C语言中函数的static局部变量是函数的内部存储器有可能使函数的功能不可预测。 错误示例如下函数其返回值即功能是不可预测的。 unsigned int integer_sum( unsigned int base )
{unsigned int index;static unsigned int sum 0;// 注意是static类型的。// 若改为auto类型则函数即变为可预测。for (index 1; index base; index){sum index;}return sum;
}检查函数所有非参数输入的有效性如数据文件、公共变量等 函数的输入主要有两种一种是参数输入另一种是全局变量、数据文件的输入即非参数输入。函数在使用输入参数之前应进行有效性检查。 函数的参数个数不超过5个 函数的参数过多会使得该函数易于受外部其他部分的代码变化的影响从而影响维护工作。函数的参数过多同时也会增大测试的工作量。 函数的参数个数不要超过5个如果超过了建议拆分为不同函数。 除打印类函数外不要使用可变长参函数。 可变长参函数的处理过程比较复杂容易引入错误而且性能也比较低使用过多的可变长参函数将导致函数的维护难度大大增加。 在源文件范围内声明和定义的所有函数除非外部可见否则应该增加static关键字 如果一个函数只是在同一文件中的其他地方调用那么就用static声明。使用static确保只是在声明它的文件中是可见的并且避免了和其他文件或库中的相同标识符发生混淆的可能性。 正确示例建议定义一个STATIC宏在调试阶段将STATIC定义为static版本发布时改为空以便于后续的打热补丁等操作。 #ifdef _DEBUG#define STATIC static#else#define STATIC#endif使用返回值而不是输出参数使用强类型避免使用 void* 。
标识符命名与定义
标识符的命名规则历来是一个敏感话题典型的命名风格如unix风格、windows风格等从来无法达成共识。实际上各种风格都有其优势也有其劣势而且往往和个人的审美观有关。我们对标识符定义主要是为了让团队的代码看起来尽可能统一有利于代码的后续阅读和修改产品可以根据自己的实际需要指定命名风格规范中不再做统一的规定。 标识符的命名要清晰、明了有明确含义同时使用完整的单词或大家基本可以理解的缩写避免使人产生误解 尽可能给出描述性名称不要节约空间让别人很快理解你的代码更重要。 正确示例 int error_number;
int number_of_completed_connection;错误示例 int n;
int nerr;
int n_comp_conns;除了常见的通用缩写以外不使用单词缩写不得使用汉语拼音 较短的单词可通过去掉“元音”形成缩写较长的单词可取单词的头几个字母形成缩写一些单词有大家公认的缩写常用单词的缩写必须统一。协议中的单词的缩写与协议保持一致。对于某个系统使用的专用缩写应该在注视或者某处做统一说明。 正确示例一些常见可以缩写的例子 argument 可缩写为 arg
buffer 可缩写为 buff
clock 可缩写为 clk
command 可缩写为 cmd
compare 可缩写为 cmp
configuration 可缩写为 cfg
device 可缩写为 dev
error 可缩写为 err
hexadecimal 可缩写为 hex
increment 可缩写为 inc
initialize 可缩写为 init
maximum 可缩写为 max
message 可缩写为 msg
minimum 可缩写为 min
parameter 可缩写为 para
previous 可缩写为 prev
register 可缩写为 reg
semaphore 可缩写为 sem
statistic 可缩写为 stat
synchronize 可缩写为 sync
temp 可缩写为 tmp产品/项目组内部应保持统一的命名风格 Unix like和windows like风格均有其拥趸产品应根据自己的部署平台选择其中一种并在产品内部保持一致。 用正确的反义词组命名具有互斥意义的变量或相反动作的函数等 正确示例 add/remove begin/end create/destroy
insert/delete first/last get/release
increment/decrement put/get add/delete
lock/unlock open/close min/max
old/new start/stop next/previous
source/target show/hide send/receive
source/destination copy/paste up/down尽量避免名字中出现数字编号除非逻辑上的确需要编号 错误示例如下命名使人产生疑惑。 #define EXAMPLE_0_TEST_
#define EXAMPLE_1_TEST_正确示例应改为有意义的单词命名。 #define EXAMPLE_UNIT_TEST_
#define EXAMPLE_ASSERT_TEST_标识符前不应添加模块、项目、产品、部门的名称作为前缀 很多已有代码中已经习惯在文件名中增加模块名这种写法类似匈牙利命名法导致文件名不可读并且带来带来如下问题 第一眼看到的是模块名而不是真正的文件功能阻碍阅读 文件名太长 文件名和模块绑定不利于维护和移植。若foo.c进行重构后从a模块挪到b模块若foo.c中有模块名则需要将文件名从a_module_foo.c改为b_module_foo.c。 平台、驱动等适配代码的标识符命名风格保持和平台 涉及到外购芯片以及配套的驱动这部分的代码变动包括为产品做适配的新增代码应该保持原有的风格。 重构/修改部分代码时应保持和原有代码的命名风格一致 根据源代码现有的风格继续编写代码有利于保持总体一致。 文件命名统一采用小写字符 因为不同系统对文件名大小写处理会不同如MS的DOS、Windows系统不区分大小写但是Linux系统则区分所以代码文件命名建议统一采用全小写字母命名。 全局变量应增加“g_” 前缀静态变量应增加“s_” 首先全局变量十分危险通过前缀使得全局变量更加醒目促使开发人员对这些变量的使用更加小心。其次从根本上说应当尽量不使用全局变量增加g_和s_前缀会使得全局变量的名字显得很丑陋从而促使开发人员尽量少使用全局变量。 禁止使用单字节命名变量但允许定义i 、j、k作为局部循环变量 不建议使用匈牙利命名法 匈牙利命名法是一种编程时的命名规范。基本原则是变量名属性类型对象描述。匈牙利命名法源于微软然而却被很多人以讹传讹的使用。而现在即使是微软也不再推荐使用匈牙利命名法。历来对匈牙利命名法的一大诟病就是导致了变量名难以阅读这和本规范的指导思想也有冲突所以本规范特意强调变量命名不应采用匈牙利命名法而应该想法使变量名为一个有意义的词或词组方便代码的阅读。 变量命名需要说明的是变量的含义而不是变量的类型。在变量命名前增加类型说明反而降低了变量的可读性更麻烦的问题是如果修改了变量的类型定义那么所有使用该变量的地方都需要修改。 使用名词或者形容词名词方式命名变量 函数命名应以函数要执行的动作命名一般采用动词或者动词名词的结构 正确示例找到当前进程的当前目录 DWORD GetCurrentDirectory( DWORD BufferLength, LPTSTR Buffer );函数指针除了前缀其他按照函数的命名规则命名 对于数值或者字符串等等常量的定义建议采用全大写字母单词之间加下划线“_”的方式命名枚举同样建议使用此方式定义 正确示例 #define PI_ROUNDED 3.14除了头文件或编译开关等特殊标识定义宏定义不能使用下划线“_”开头和结尾 一般来说‟_‟开头、结尾的宏都是一些内部的定义ISO/IEC 9899俗称C99中有如下的描述6.10.8 Predefined macro names: None of these macro names (这里上面是一些内部定义的宏的描述)nor the identifier defined, shall be the subject of a #define or a #undef preprocessing directive. Any other predefined macro names shall begin with a leading underscore followed by an uppercase letter or a second underscore.
变量 一个变量只有一个功能不能把一个变量用作多种用途 一个变量只用来表示一个特定功能不能把一个变量作多种用途即同一变量取值不同时其代表的意义也不同。 错误示例具有两种功能的反例 WORD DelRelTimeQue( void )
{WORD Locate;Locate 3; Locate DeleteFromQue(Locate); /* Locate具有两种功能位置和函数DeleteFromQue的返回值 */return Locate;
}正确做法使用两个变量 WORD DelRelTimeQue( void )
{WORD Ret;WORD Locate;Locate 3;Ret DeleteFromQue(Locate);return Ret;
}结构功能单一不要设计面面俱到的数据结构 相关的一组信息才是构成一个结构体的基础结构的定义应该可以明确的描述一个对象而不是一组相关性不强的数据的集合。设计结构时应力争使结构代表一种现实事务的抽象而不是同时代表多种。结构中的各元素应代表同一事务的不同侧面而不应把描述没有关系或关系很弱的不同事务的元素放到同一结构中。 错误示例如下结构不太清晰、合理。 typedef struct STUDENT_STRU
{unsigned char name[32]; /* students name */unsigned char age; /* students age */unsigned char sex; /* students sex, as follows *//* 0 - FEMALE; 1 - MALE */unsigned char teacher_name[32]; /* the student teachers name */unsigned char teacher_sex; /* his teacher sex */
} STUDENT;正确示例若改为如下会更合理些。 typedef struct TEACHER_STRU
{unsigned char name[32]; /* teacher name */unsigned char sex; /* teacher sex, as follows *//* 0 - FEMALE; 1 - MALE */unsigned int teacher_ind; /* teacher index */
} TEACHER;typedef struct STUDENT_STRU
{unsigned char name[32]; /* students name */unsigned char age; /* students age */unsigned char sex; /* students sex, as follows *//* 0 - FEMALE; 1 - MALE */unsigned int teacher_ind; /* his teacher index */
} STUDENT; 不用或者少用全局变量 单个文件内部可以使用static的全局变量可以将其理解为类的私有成员变量。 全局变量应该是模块的私有数据不能作用对外的接口使用使用static类型定义可以有效防止外部文件的非正常访问建议定义一个STATIC宏在调试阶段将STATIC定义为static版本发布时改为空以便于后续的打补丁等操作。 防止局部变量与全局变量同名 尽管局部变量和全局变量的作用域不同而不会发生语法错误但容易使人误解。 通讯过程中使用的结构必须注意字节序 通讯报文中字节序是一个重要的问题我司设备使用的CPU类型复杂多样大小端、32位/64位的处理器也都有如果结构会在报文交互过程中使用必须考虑字节序问题。由于位域在不同字节序下表现看起来差别更大所以更需要注意对于这种跨平台的交互数据成员发送前都应该进行主机序到网络序的转换接收时也必须进行网络序到主机序的转换。 严禁使用未经初始化的变量作为右值 在首次使用前初始化变量初始化的地方离使用的地方越近越好。 降低全局变量耦合度 构造仅有一个模块或函数可以修改、创建而其余有关模块或函数只访问的全局变量防止多个不同模块或函数都可以修改、创建同一全局变量的现象。 使用面向接口编程思想通过 API 访问数据如果本模块的数据需要对外部模块开放 应提供接口函数来设置、获取同时注意全局数据的访问互斥 避免直接暴露内部数据给外部模型使用是防止模块间耦合最简单有效的方法。定义的接口应该有比较明确的意义比如一个风扇管理功能模块有自动和手动工作模式那么设置、查询工作模块就可以定义接口为SetFanWorkModeGetFanWorkMode查询转速就可以定义为GetFanSpeed风扇支持节能功能开关可以定义EnabletFanSavePower等。 明确全局变量的初始化顺序避免跨模块的初始化依赖 系统启动阶段使用全局变量前要考虑到该全局变量在什么时候初始化使用全局变量和初始化全局变量两者之间的时序关系谁先谁后一定要分析清楚不然后果往往是低级而又灾难性的。 尽量减少没有必要的数据类型默认转换与强制转换 当进行数据类型强制转换时其数据的意义、转换后的取值等都有可能发生变化而这些细节若考虑不周就很有可能留下隐患。 错误示例如下赋值多数编译器不产生告警但值的含义还是稍有变化。 char ch;
unsigned short int exam;
ch -1;
exam ch; // 编译器不产生告警此时exam为0xFFFF。宏、常量 用宏定义表达式时要使用完备的括号 因为宏只是简单的代码替换不会像函数一样先将参数计算后再传递。 错误示例如下定义的宏都存在一定的风险 #define RECTANGLE_AREA(a, b) a * b
#define RECTANGLE_AREA(a, b) (a * b)
#define RECTANGLE_AREA(a, b) (a) * (b)正确示例 #define RECTANGLE_AREA(a, b) ((a) * (b))包含多条语句的函数宏须放在do{ } while(0)中。 将宏所定义的多条表达式放在大括号中 使用宏时不允许参数发生变化 错误示例 #define SQUARE(a) ((a) * (a))
int a 5;
int b;
b SQUARE(a); // 结果a 7即执行了两次增。正确示例 b SQUARE(a);
a; // 结果a 6即只执行了一次增。同时也建议即使函数调用也不要在参数中做变量变化操作因为可能引用的接口函数在某个版本升级后变成了一个兼容老版本所做的一个宏结果可能不可预知。 不允许直接使用魔鬼数字 使用魔鬼数字的弊端代码难以理解如果一个有含义的数字多处使用一旦需要修改这个数值代价惨重。 使用明确的物理状态或物理意义的名称能增加信息并能提供单一的维护点。 解决途径对于局部使用的唯一含义的魔鬼数字可以在代码周围增加说明注释也可以定义局部const变量变量命名自注释。对于广泛使用的数字必须定义const全局变量/宏同样变量/宏命名应是自注释的。0作为一个特殊的数字作为一般默认值使用没有歧义时不用特别定义。 除非必要应尽可能使用函数代替宏 宏对比函数有一些明显的缺点 宏缺乏类型检查不如函数调用检查严格宏展开可能会产生意想不到的副作用如#define SQUARE(a) (a) * (a)这样的定义如果是SQUARE(i)就会导致i被加两次如果是函数调用double square(double a) {return a * a;}则不会有此副作用以宏形式写的代码难以调试难以打断点不利于定位问题宏如果调用的很多会造成代码空间的浪费不如函数空间效率高。 错误示例下面的代码无法得到想要的结果 #define MAX_MACRO(a, b) ((a) (b) ? (a) : (b))
int MAX_FUNC(int a, int b) {return ((a) (b) ? (a) : (b));
}
int testFunc()
{unsigned int a 1;int b -1;printf(MACRO: max of a and b is: %d\n, MAX_MACRO(a, b));printf(FUNC : max of a and b is: %d\n, MAX_FUNC(a, b));return 0;
}上面宏代码调用中由于宏缺乏类型检查a和b的比较变成无符号数的比较结果是a b所以a只加了一次所以最终的输出结果是 MACRO: max of a and b is: -1FUNC : max of a and b is: 2常量建议使用 const 定义代替宏 因为#define经常被认为好象不是语言本身的一部分 “尽量用编译器而不用预处理”。看下面的语句 #define ASPECT_RATIO 1.653编译器会永远也看不到ASPECT_RATIO这个符号名因为在源码进入编译器之前它会被预处理程序去掉于是ASPECT_RATIO不会加入到符号列表中。如果涉及到这个常量的代码在编译时报错就会很令人费解因为报错信息指的是1.653而不是ASPECT_RATIO。如果ASPECT_RATIO不是在你自己写的头文件中定义的你就会奇怪1.653是从哪里来的甚至会花时间跟踪下去。这个问题也会出现在符号调试器中因为同样地你所写的符号名不会出现在符号列表中。 解决这个问题的方案很简单不用预处理宏定义一个常量 const double ASPECT_RATIO 1.653;这种方法很有效但有两个特殊情况要注意。首先定义指针常量时会有点不同。因为常量定义一般是放在头文件中许多源文件会包含它除了指针所指的类型要定义成const外重要的是指针也经常要定义成const。例如要在头文件中定义一个基于char*的字符串常量你要写两次const const char * const authorName Scott Meyers;宏定义中尽量不使用 return 、 goto 、 continue 、 break等改变程序流程的语句 如果在宏定义中使用这些改变流程的语句很容易引起资源泄漏问题使用者很难自己察觉。 错误示例在某头文件中定义宏CHECK_AND_RETURN #define CHECK_AND_RETURN(cond, ret) {if (cond NULL_PTR) {return ret;}}
//然后在某函数中使用(只说明问题代码并不完整):
pMem1 VOS_MemAlloc(...);
CHECK_AND_RETURN(pMem1 , ERR_CODE_XXX)
pMem2 VOS_MemAlloc(...);
CHECK_AND_RETURN(pMem2 , ERR_CODE_XXX) /*此时如果pMem2NULL_PTR则pMem1未释放函数就返回了造成内存泄漏。*/所以说类似于CHECK_AND_RETURN这些宏虽然能使代码简洁但是隐患很大使用须谨慎。
表达式 表达式的值在标准所允许的任何运算次序下都应该是相同的 含有变量自增或自减运算的表达式中禁止再次使用该变量。 函数调用不要作为另一个函数的参数使用否则对于代码的调试、阅读都不利 错误示例如下代码不合理仅用于说明当函数作为参数时由于参数压栈次数不是代码可以控制的可能造成未知的输出 int g_var;
int fun1()
{g_var 10;return g_var;
}
int fun2()
{g_var 100;return g_var;
}
int main(int argc, char *argv[], char *envp[])
{g_var 1;printf(func1: %d, func2: %d\n, fun1(), fun2());g_var 1;printf(func2: %d, func1: %d\n, fun2(), fun1());
}上面的代码使用断点调试起来也比较麻烦阅读起来也不舒服所以不要为了节约代码行而写这种代码。 赋值语句不要写在 if 等语句中或者作为函数的参数使用 因为if语句中会根据条件依次判断如果前一个条件已经可以判定整个条件则后续条件语句不会再运行所以可能导致期望的部分赋值没有得到运行。 错误示例 int main(int argc, char *argv[], char *envp[])
{int a 0;int b;if ((a 0) || ((b fun1()) 10)){printf(a: %d\n, a);}printf(b: %d\n, b);
}作用函数参数来使用参数的压栈顺序不同可能导致结果未知。 用括号明确表达式的操作顺序避免过分依赖默认优先级 使用括号强调所使用的操作符防止因默认的优先级与设计思想不符而导致程序出错同时使得代码更为清晰可读然而过多的括号会分散代码使其降低了可读性。 赋值操作符不能使用在产生布尔值的表达式上 示例 x y;
if (x ! 0)
{foo ();
}不能写成 if (( x y ) ! 0)
{foo ();
}或者更坏的 if (x y)
{foo ();
}注释 优秀的代码可 以自我解释不通过注释即可轻易读懂 优秀的代码不写注释也可轻易读懂注释无法把糟糕的代码变好需要很多注释来解释的代码往往存在坏味道需要重构。 错误示例注释不能消除代码的坏味道 /* 判断m是否为素数*/
/* 返回值: 是素数: 不是素数*/
int p(int m)
{int k sqrt(m);for (int i 2; i k; i)if (m % i 0)break; /* 发现整除表示m不为素数结束遍历*//* 遍历中没有发现整除的情况返回*/if (i k)return 1;/* 遍历中没有发现整除的情况返回*/elsereturn 0;
}重构代码后不需要注释 int IsPrimeNumber(int num)
{int sqrt_of_num sqrt (num);for (int i 2; i sqrt_of_num; i){if (num % i 0){return FALSE;}}return TRUE;
}注释的内容要清楚、明了含义准确防止注释二义性 有歧义的注释反而会导致维护者更难看懂代码正如带两块表反而不知道准确时间。 在代码的功能、意图层次上进行注释即注释解释 代码难以直接表达的意图 而不是重复描述代码 注释的目的是解释代码的目的、功能和采用的方法提供代码以外的信息帮助读者理解代码防止没必要的重复注释信息。对于实现代码中巧妙的、晦涩的、有趣的、重要的地方加以注释。注释不是为了名词解释what而是说明用途why。 修改代码时维护代码周边的所有注释以保证注释与代码的一致性不再有用的注释要删除 不要将无用的代码留在注释中随时可以从源代码配置库中找回代码即使只是想暂时排除代码也要留个标注不然可能会忘记处理它。 文件头部应进行注释注释必须列出版权说明、版本号、生成日期、作者姓名、工号、内容、功能说明、与其它文件的关系、修改日志等头文件的注释中还应有函数功能简要说明 函数声明处注释描述函数功能、性能及用法包括输入和输出参数、函数返回值、可重入的要求等定义处详细描述函数功能和实现要点如实现的简要步骤、实现的理由、 设计约束等 重要的、复杂的函数提供外部使用的接口函数应编写详细的注释。 全局变量要有较详细的注释包括对其功能、取值范围以及存取时注意事项等的说明 正确示例 /* The ErrorCode when SCCP translate */
/* Global Title failure, as follows */ /* 变量作用、含义*/
/* 0 SUCCESS 1 GT Table error */
/* 2 GT error Others no use */ /* 变量取值范围*/
/* only function SCCPTranslate() in */
/* this modual can modify it, and other */
/* module can visit it through call */
/* the function GetGTTransErrorCode() */ /* 使用方法*/
BYTE g_GTTranErrorCode;注释应放在其代码上方相邻位置或右方不可放在下面如放于上方则需与其上面的代码用空行隔开且与下方代码缩进相同 正确示例 /* active statistic task number */
#define MAX_ACT_TASK_NUMBER 1000
#define MAX_ACT_TASK_NUMBER 1000 /* active statistic task number */可按如下形式说明枚举/数据/联合结构。 /* sccp interface with sccp user primitive message name */
enum SCCP_USER_PRIMITIVE
{N_UNITDATA_IND, /* sccp notify sccp user unit data come */N_NOTICE_IND, /* sccp notify user the No.7 network can not transmission this message */N_UNITDATA_REQ, /* sccp users unit data transmission request*/
};对于 switch语句下的case语句如果因为特殊情况需要处理完一个case后进入下一个case处理必须在该case语句处理完、下一个case语句前加上明确的注释 这样比较清楚程序编写者的意图有效防止无故遗漏break语句。 case CMD_FWD:ProcessFwd();/* now jump into c ase CMD_A */
case CMD_A:ProcessA();break;
//对于中间无处理的连续case已能较清晰说明意图不强制注释。
switch (cmd_flag) {case CMD_A:case CMD_B:{ProcessCMD();break;}……
}避免在注释中使用缩写除非是业界通用或子系统内标准化的缩写 同一产品或项目组统一注释风格 避免在一行代码或表达式的中间插入注释 除非必要不应在代码或表达中间插入注释否则容易使代码可理解性变差 注释应考虑程序易读及外观排版的因素使用的语言若是中、英兼有的建议多使用中文除非能用非常流利准确的英文表达对于有外籍员工的由产品确定注释语言 注释语言不统一影响程序易读性和外观排版出于对维护人员的考虑建议使用中文。 文件头、函数头、全局常量变量、类型定义的注释格式采用工具可识别的格式 采用工具可识别的注释格式例如doxygen格式方便工具导出注释形成帮助文档。以doxygen格式为例文件头函数和全部变量的注释的示例如下
排版与格式 程序块采用缩进风格编写 每级缩进为4个空格 相对独立的程序块之间、变量说明之后必须加空行 一条语句不能过长如不能拆分需要分行写。一行到底多少字符换行比较合适产品可以自行确定 对于目前大多数的PC来说132比较合适80/132是VTY常见的行宽值对于新PC宽屏显示器较多的产品来说可以设置更大的值。换行时有如下建议 换行时要增加一级缩进使代码可读性更好低优先级操作符处划分新行换行时操作符应该也放下来放在新行首换行时建议一个完整的语句放在一行不要根据字符数断行。 正确示例 if ((temp_flag_var TEST_FLAG)
(((temp_counter_var - TEST_COUNT_BEGIN) % TEST_COUNT_MODULE) TEST_COUNT_THRESHOLD))
{// process code
}多个短语句包括赋值语句不允许写在同一行内 即一行只写一条语句 错误示例 int a 5; int b 10; //不好的排版正确示例 int a 5;
int b 10;if 、 for 、 do 、 while 、 case 、 switch 、 default 等语句独占一行 执行语句必须用缩进风格写属于if、for、do、while、case、switch、default等下一个缩进级别 一般写if、for、do、while等语句都会有成对出现的{}对此有如下建议可以参考if、for、do、while等语句后的执行语句建议增加成对的“{}”如果if/else配套语句中有一个分支有“{}”那么另一个分支即使一行代码也建议增加“{}”添加“{”的位置可以在if等语句后也可以独立占下一行独立占下一行时可以和if在一个缩进级别也可以在下一个缩进级别但是如果if语句很长或者已经有换行建议“{”使用独占一行的写法。 在两个以上的关键字、变量、常量进行对等操作时如 - * ! 它们之间的操作符之前、之后或者前后要加空格 进行非对等操作时如果是关系密切的立即操作符如 ~后不应加空格 采用这种松散方式编写代码的目的是使代码更加清晰。 在已经非常清晰的语句中没有必要再留空格如括号内侧(即左括号后面和右括号前面)不需要加空格多重括号间不必加空格因为在C语言中括号已经是最清晰的标志了。在长语句中如果需要加的空格非常多那么应该保持整体清晰而在局部不加空格。给操作符留空格时不要连续留两个以上空格。 正确示例 逗号、分号只在后面加空格。 int a, b, c;比较操作符, 赋值操作符“、 “”算术操作符”“、”%“逻辑操作符”“、”“位域操作符”“、”^等双目操作符的前后加空格。 if (current_time MAX_TIME_VALUE)
a b c;
a * 2;
a b ^ 2;“!”、“~”、“”、“–”、“”地址操作符等单目操作符前后不加空格。 *p a; // 内容操作*与内容之间
flag !is_empty; // 非操作!与内容之间
p mem; // 地址操作 与内容之间
i; “-”、.前后不加空格。 p-id pid; // -指针前后不加空格if、for、while、switch等与后面的括号间应加空格使if等关键字更为突出、明显。 if (a b c d)注释符包括/**/、//与注释内容之间要用一个空格进行分隔 源程序中关系较为紧密的代码应尽可能相邻 排版风格 KR对齐风格函数左大括号另起一行其他跟随语句行末优点是代码阅读的节奏连续。函数声明定义——返回类型与函数名同一行参数合理对齐。初始化换行时要有缩进或合理对齐左大括号放行末右大括号另起一行。水平空格应突出关键字和重要信息避免不必要的留白
代码编辑编译 使用编译器的最高告警级别理解所有的告警通过修改代码而不是降低告警级别来消除所有告警 编译器是你的朋友如果它发出某个告警这经常说明你的代码中存在潜在的问题。 在产品软件项目组中要统一编译开关、静态检查选项以及相应告警清除策略 如果必须禁用某个告警应尽可能单独局部禁用并且编写一个清晰的注释说明为什么屏蔽。某些语句经编译/静态检查产生告警但如果你认为它是正确的那么应通过某种手段去掉告警信息。 本地构建工具如 PC-Lint的配置应该和持续集成的一致 两者一致避免经过本地构建的代码在持续集成上构建失败 使用版本控制配置管理系统及时签入通过本地构建的代码确保签入的代码不会影响构建成功及时签入代码降低集成难度。 要小心地使用编辑器提供的块拷贝功能编程
其他设置
命名规则
类型命名
类型包括类(class、结构体(struct)、类型定义(typedef)、枚举(enum)等。 类型名称每个单词首字母大写采用驼峰形式定义的结构体类型以Type结尾。
// 类(class)
class TestClass
{};// 结构体(struct)
struct TestStruct
{};
// 类型定义(typedef)
typedef struct TestType
{};
// 枚举(enum)
enum TestEnum
{};// 名字空间 全小写字母。
namespace myNamespace
{};参考MISRA-C编程规范
常用的缩写 argument - arg temp -tmp error -err clock -clk statistic -stat increment -inc compare -cmp register -reg previous -prev device -dev buffer -buf semaphore -sem message -msg command -cmd synchronize -sync parameter -para configuration -cfg
常用单词/短语 增加最常见使用create和add但最好根据英语的语义进行区分这有助于理解create代表创建add代表增加。比如要创建一个Student用createStudent要比用addStudent好想想如果有个类叫Clazz(班级避开Java关键字现在要把一个Student加入到一个ClazzClazz很容易就定义了一个 addStudentStudent student)的方法那么就比较容易混淆。 修改常见的有alter、update、modify个人觉得modify最准确。 查询对于获取单个对象可以用get或load但个人建议用get对于不分条件列举用list对于有条件查询用search最好不要用findfind在英文了强调结果是“找到”的意思你提供一个“查询”方法不保证输入的条件总能“找到”结果。 删除常见的有delete和remove但删除建议用delete因为remove有“移除”的意思参考Clazz的例子就可以理解从班级移除一个学生会用removeStudent。 block design??程序块设计 完成 [动]accomplish; complete; fulfil; finish; achieve ; 状态?mode [科技] phase [科技] state [科技] status [科技]; 初始化initialization ?init 配置 处理 process 延时delay ?Dly?
常用的反义词组 add / remove? ?? ? begin / end? ?? ???create / destroy insert / delete? ?? ? first / last? ?? ?? ?get / release increment / decrement? ?? ?? ?? ?? ???put / get add / delete? ?? ?? ?lock / unlock? ?? ?open / close min / max? ?? ?? ? old / new? ?? ?? ?start / stop next / previous? ?? ?source / target? ???show / hide send / receive? ?? ? source / destination cut / paste? ?? ?? ? up / down ?? head / tail top / bottom ok fail success error right ?wrong true ?false 常用类命名 布局类header,footer,container,main,content,aside,page,section 包裹类wrap,inner 区块类region,block,box 结构类hd,bd,ft,top,bottom,left,right,middle,col,row,grid,span 列表类list,item,field 主次类primary,secondary,sub,minor 大小类s,m,l,xl,large,small 状态类active,current,checked,hover,fail,success,warn,error,on,off 导航类nav,prev,next,breadcrumb,forward,back,indicator,paging,first,last 交互类tips,alert,modal,pop,panel,tabs,accordion,slide,scroll,overlay 星级类rate,star 分割类group,seperate,divider 等分类full,half.third,quarter 表格类table,tr,td,cell,row 图片类img,thumbnail,original,album,gallery 语言类en,cn 论坛类forum,bbs,topic,post 方向类up, down,left,right 其他定义类:btn,close,ok,cancel,switch,link,title,info,intro,more,icon,form,lable,searcch,contact,phone,date,email,user,view,loading…
协议术语与定义 主站 primary station 从站 secondary station 上行传输 upstream 下行传输 downstream 中继 relaying 网关 gateway 路由器 router 节点 node 端节点 end node 中间节点 intermediate node 跳转 hop 帧 frame 块 block 包 package 帧格式 L-域DA-域SA-域FC-域DLY-域Data-域FCS长度域目标地址域源地址域帧控制域延时域数据域帧校验域 网络层信息包的格式 NCtrlTIDDestinSourceTTLSNRNodesCurrentAddr.ListApp.data网络控制传输识别目的地址源地址生存时间信噪比节点数等于跳转数1当前节点节点地址信息应用层数据 C/C code #ifdef __cplusplus //c编译环境中才会定义__cplusplus (plus就是的意思) extern “C” { //告诉编译器下面的函数是c语言函数因为c和c语言对函数的编译转换不一样主要是c中存在重载c中没有重载 #endif 这样编码的作用就是 如果此头文件是在c中使用的就是一个.cpp文件include此头文件而不是一个.c文件 那么函数名称粉碎方式仍然使用C中的方式。(就是此函数编译后在object文件中的内部名称和C中是兼容的) 。 如 void foo1();? 如果c文件包含了它生成的object文件中此函数被命名为 c_foo1而在cpp文件中包含了它生成的object中此函数命名为cpp_foo1。使用extern “C后可以强制使其仍然为c_foo1”。 目的就是为了在c和cpp中互相调用函数命名一致否则会出现链接错误。 C编译器编译时生成函数名称的规则和C编译器不一样如果是在C中使用用C语言编译器编译生成的库文件就需要用这个防止C编译器链接不到函数。
其他
编译器配色
经典字体与配色
SI经典配色RGB 背景经典灰58 58 58 文本167 251 254 非活动文本169 185 233 行号201 211 241 关键字0 255 84 字符串158 235 187 数字255 128 64 注释179 193 235 用户关键字0 255 128 运算符255 119 255字体1.inconsolata 2.consolas 3.Courier new 4.Courier其他背景色 豆沙绿187 223 188紫金色53 35 161黑绿0 102 0
参考
1. 菊花厂C语言编程10大规范 2. 万字 | 菊花厂C语言编程10大规范 3. 据说程序员最怕命名这个 6300 Star 的手册能帮上忙 4. 写代码时候的命名规则、命名规范、命名常用词汇 文章转载自: http://www.morning.mzzqs.cn.gov.cn.mzzqs.cn http://www.morning.jllnh.cn.gov.cn.jllnh.cn http://www.morning.syssdz.cn.gov.cn.syssdz.cn http://www.morning.wkhfg.cn.gov.cn.wkhfg.cn http://www.morning.fnpmf.cn.gov.cn.fnpmf.cn http://www.morning.fkcjs.cn.gov.cn.fkcjs.cn http://www.morning.prjty.cn.gov.cn.prjty.cn http://www.morning.gpcy.cn.gov.cn.gpcy.cn http://www.morning.nmqdk.cn.gov.cn.nmqdk.cn http://www.morning.rtkz.cn.gov.cn.rtkz.cn http://www.morning.tzjqm.cn.gov.cn.tzjqm.cn http://www.morning.ghqyr.cn.gov.cn.ghqyr.cn http://www.morning.ogzjf.cn.gov.cn.ogzjf.cn http://www.morning.nhzzn.cn.gov.cn.nhzzn.cn http://www.morning.dzgyr.cn.gov.cn.dzgyr.cn http://www.morning.bfysg.cn.gov.cn.bfysg.cn http://www.morning.qmzwl.cn.gov.cn.qmzwl.cn http://www.morning.woyoua.com.gov.cn.woyoua.com http://www.morning.wyctq.cn.gov.cn.wyctq.cn http://www.morning.ghqyr.cn.gov.cn.ghqyr.cn http://www.morning.mlfgx.cn.gov.cn.mlfgx.cn http://www.morning.srgsb.cn.gov.cn.srgsb.cn http://www.morning.bfgbz.cn.gov.cn.bfgbz.cn http://www.morning.pwzzk.cn.gov.cn.pwzzk.cn http://www.morning.wrlcy.cn.gov.cn.wrlcy.cn http://www.morning.glkhx.cn.gov.cn.glkhx.cn http://www.morning.jqwpw.cn.gov.cn.jqwpw.cn http://www.morning.krbjb.cn.gov.cn.krbjb.cn http://www.morning.sdhmn.cn.gov.cn.sdhmn.cn http://www.morning.gwtbn.cn.gov.cn.gwtbn.cn http://www.morning.sypzg.cn.gov.cn.sypzg.cn http://www.morning.qkgwz.cn.gov.cn.qkgwz.cn http://www.morning.kpyyf.cn.gov.cn.kpyyf.cn http://www.morning.lnyds.cn.gov.cn.lnyds.cn http://www.morning.kpgbz.cn.gov.cn.kpgbz.cn http://www.morning.ftgwj.cn.gov.cn.ftgwj.cn http://www.morning.rgxcd.cn.gov.cn.rgxcd.cn http://www.morning.lhygbh.com.gov.cn.lhygbh.com http://www.morning.ldhbs.cn.gov.cn.ldhbs.cn http://www.morning.kwwkm.cn.gov.cn.kwwkm.cn http://www.morning.syynx.cn.gov.cn.syynx.cn http://www.morning.bxbnf.cn.gov.cn.bxbnf.cn http://www.morning.dygqq.cn.gov.cn.dygqq.cn http://www.morning.przc.cn.gov.cn.przc.cn http://www.morning.wjjxr.cn.gov.cn.wjjxr.cn http://www.morning.jgmdr.cn.gov.cn.jgmdr.cn http://www.morning.rfpxq.cn.gov.cn.rfpxq.cn http://www.morning.wrlxt.cn.gov.cn.wrlxt.cn http://www.morning.fdrb.cn.gov.cn.fdrb.cn http://www.morning.wjqyt.cn.gov.cn.wjqyt.cn http://www.morning.gsrh.cn.gov.cn.gsrh.cn http://www.morning.zylrk.cn.gov.cn.zylrk.cn http://www.morning.youprogrammer.cn.gov.cn.youprogrammer.cn http://www.morning.rcgzg.cn.gov.cn.rcgzg.cn http://www.morning.nywrm.cn.gov.cn.nywrm.cn http://www.morning.tmpsc.cn.gov.cn.tmpsc.cn http://www.morning.sfwcb.cn.gov.cn.sfwcb.cn http://www.morning.pypqf.cn.gov.cn.pypqf.cn http://www.morning.ahscrl.com.gov.cn.ahscrl.com http://www.morning.xinxianzhi005.com.gov.cn.xinxianzhi005.com http://www.morning.znqfc.cn.gov.cn.znqfc.cn http://www.morning.rppf.cn.gov.cn.rppf.cn http://www.morning.tcsdlbt.cn.gov.cn.tcsdlbt.cn http://www.morning.hjrjy.cn.gov.cn.hjrjy.cn http://www.morning.nqbpz.cn.gov.cn.nqbpz.cn http://www.morning.lwrcg.cn.gov.cn.lwrcg.cn http://www.morning.jqbmj.cn.gov.cn.jqbmj.cn http://www.morning.djmdk.cn.gov.cn.djmdk.cn http://www.morning.pzlcd.cn.gov.cn.pzlcd.cn http://www.morning.alive-8.com.gov.cn.alive-8.com http://www.morning.blqmn.cn.gov.cn.blqmn.cn http://www.morning.gpmrj.cn.gov.cn.gpmrj.cn http://www.morning.xmjzn.cn.gov.cn.xmjzn.cn http://www.morning.hmnhp.cn.gov.cn.hmnhp.cn http://www.morning.pkrtz.cn.gov.cn.pkrtz.cn http://www.morning.lmxrt.cn.gov.cn.lmxrt.cn http://www.morning.sfsjh.cn.gov.cn.sfsjh.cn http://www.morning.c-ae.cn.gov.cn.c-ae.cn http://www.morning.xnnxp.cn.gov.cn.xnnxp.cn http://www.morning.fkgct.cn.gov.cn.fkgct.cn