华为C语言编程规范_c语言编程规范 华为,2024年最新国内一线互联网公司面试题汇总-程序员宅基地

技术标签: 2024年程序员学习  c语言  华为  服务器  

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Golang全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注go)
img

正文

5、 可重入函数应避免使用共享变量;若需要使用,则应通过互斥手段(关中断、信号量)对其加以保护

可重入函数是指可能被多个任务并发调用的函数。在多任务操作系统中,函数具有可重入性是多个任务可以共用此函数的必要条件。共享变量指的全局变量和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;

}

6、对参数的合法性检查,由调用者负责还是由接口函数负责,应在项目组/模块内应统一规定。缺省由调用者负责。

对于模块间接口函数的参数的合法性检查这一问题,往往有两个极端现象,即:要么是调用者和被调用者对参数均不作合法性检查,结果就遗漏了合法性检查这一必要的处理过程,造成问题隐患;要么就是调用者和被调用者均对参数进行合法性检查,这种情况虽不会造成问题,但产生了冗余代码,降低了效率。

7、对函数的错误返回码要全面处理

一个函数(标准库中的函数/第三方库函数/用户定义的函数)能够提供一些指示错误发生的方法。这可以通过使用错误标记、特殊的返回数据或者其他手段,不管什么时候函数提供了这样的机制,调用程序应该在函数返回时立刻检查错误指示。

8、设计高扇入,合理扇出(小于7)的函数

扇出是指一个函数直接调用(控制)其它函数的数目,而扇入是指有多少上级函数调用它。

img

扇出过大,表明函数过分复杂,需要控制和协调过多的下级函数;而扇出过小,例如:总是1,表明函数的调用层次可能过多,这样不利于程序阅读和函数结构的分析,并且程序运行时会对系统资源如堆栈空间等造成压力。通常函数比较合理的扇出(调度函数除外)通常是3~5。

扇出太大,一般是由于缺乏中间层次,可适当增加中间层次的函数。扇出太小,可把下级函数进一步分解多个函数,或合并到上级函数中。当然分解或合并函数时,不能改变要实现的功能,也不能违背函数间的独立性。扇入越大,表明使用此函数的上级函数越多,这样的函数使用效率高,但不能违背函数间的独立性而单纯地追求高扇入。公共模块中的函数及底层函数应该有较高的扇入。

较良好的软件结构通常是顶层函数的扇出较高,中层函数的扇出较少,而底层函数则扇入到公共模块中。

9、废弃代码(没有被调用的函数和变量) ) 要及时清除

程序中的废弃代码不仅占用额外的空间,而且还常常影响程序的功能与性能,很可能给程序的测试、维护等造成不必要的麻烦。

10、函数不变参数使用const

不变的值更易于理解/跟踪和分析,把const作为默认选项,在编译时会对其进行检查,使代码更牢固/更安全。

正确示例:C99标准 7.21.4.4 中strncmp 的例子,不变参数声明为const。

int strncmp(const char *s1, const char *s2, register size_t n)

{

register unsigned char u1, u2;

while (n-- > 0)

{

u1 = (unsigned char) *s1++;

u2 = (unsigned char) *s2++;

if (u1 != u2)

{

return u1 - u2;

}

if (u1 == ‘\0’)

{

return 0;

}

}

return 0;

}

11、函数应避免使用全局变量、静态局部变量和 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;

}

12、检查函数所有非参数输入的有效性,如数据文件、公共变量等

函数的输入主要有两种:一种是参数输入;另一种是全局变量、数据文件的输入,即非参数输入。函数在使用输入参数之前,应进行有效性检查。

13、 函数的参数个数不超过5个

函数的参数过多,会使得该函数易于受外部(其他部分的代码)变化的影响,从而影响维护工作。函数的参数过多同时也会增大测试的工作量。

函数的参数个数不要超过5个,如果超过了建议拆分为不同函数。

14、除打印类函数外,不要使用可变长参函数。

可变长参函数的处理过程比较复杂容易引入错误,而且性能也比较低,使用过多的可变长参函数将导致函数的维护难度大大增加。

15、在源文件范围内声明和定义的所有函数,除非外部可见,否则应该增加static关键字

如果一个函数只是在同一文件中的其他地方调用,那么就用static声明。使用static确保只是在声明它的文件中是可见的,并且避免了和其他文件或库中的相同标识符发生混淆的可能性。

正确示例:建议定义一个STATIC宏,在调试阶段,将STATIC定义为static,版本发布时,改为空,以便于后续的打热补丁等操作。

#ifdef _DEBUG

#define STATIC static

#else

#define STATIC

#endif

3、标识符命名与定义

标识符的命名规则历来是一个敏感话题,典型的命名风格如unix风格、windows风格等,从来无法达成共识。实际上,各种风格都有其优势也有其劣势,而且往往和个人的审美观有关。我们对标识符定义主要是为了让团队的代码看起来尽可能统一,有利于代码的后续阅读和修改,产品可以根据自己的实际需要指定命名风格,规范中不再做统一的规定。

1、标识符的命名要清晰、明了,有明确含义,同时使用完整的单词或大家基本可以理解的缩写,避免使人产生误解

尽可能给出描述性名称,不要节约空间,让别人很快理解你的代码更重要。

正确示例:

int error_number;

int number_of_completed_connection;

错误示例:

int n;

int nerr;

int n_comp_conns;

2、除了常见的通用缩写以外,不使用单词缩写,不得使用汉语拼音

较短的单词可通过去掉“元音”形成缩写,较长的单词可取单词的头几个字母形成缩写,一些单词有大家公认的缩写,常用单词的缩写必须统一。协议中的单词的缩写与协议保持一致。对于某个系统使用的专用缩写应该在注视或者某处做统一说明。

正确示例:一些常见可以缩写的例子:

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

3、产品/项目组内部应保持统一的命名风格

Unix like和windows like风格均有其拥趸,产品应根据自己的部署平台,选择其中一种,并在产品内部保持一致。

4、用正确的反义词组命名具有互斥意义的变量或相反动作的函数等

正确示例:

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

5、尽量避免名字中出现数字编号,除非逻辑上的确需要编号

错误示例:如下命名,使人产生疑惑。

#define EXAMPLE_0_TEST_

#define EXAMPLE_1_TEST_

正确示例:应改为有意义的单词命名。

#define EXAMPLE_UNIT_TEST_

#define EXAMPLE_ASSERT_TEST_

6、标识符前不应添加模块、项目、产品、部门的名称作为前缀

很多已有代码中已经习惯在文件名中增加模块名,这种写法类似匈牙利命名法,导致文件名不可读,并且带来带来如下问题:

  • 第一眼看到的是模块名,而不是真正的文件功能,阻碍阅读;
  • 文件名太长;
  • 文件名和模块绑定,不利于维护和移植。若foo.c进行重构后,从a模块挪到b模块,若foo.c
  • 中有模块名,则需要将文件名从a_module_foo.c改为b_module_foo.c。

7、平台/ / 驱动等适配代码的标识符命名风格保持和平台

涉及到外购芯片以及配套的驱动,这部分的代码变动(包括为产品做适配的新增代码),应该保持原有的风格。

8、重构/修改部分代码时,应保持和原有代码的命名风格一致

根据源代码现有的风格继续编写代码,有利于保持总体一致。

9、文件命名统一采用小写字符

因为不同系统对文件名大小写处理会不同(如MS的DOS、Windows系统不区分大小写,但是Linux系统则区分),所以代码文件命名建议统一采用全小写字母命名。

10、全局变量应增加“g_” 前缀,静态变量应增加“s_”

首先,全局变量十分危险,通过前缀使得全局变量更加醒目,促使开发人员对这些变量的使用更加小心。

其次,从根本上说,应当尽量不使用全局变量,增加g_和s_前缀,会使得全局变量的名字显得很丑陋,从而促使开发人员尽量少使用全局变量。

11、禁止使用单字节命名变量,但 允许 定义i 、j、k作为局部循环变量

12、 不建议使用匈牙利命名法

匈牙利命名法是一种编程时的命名规范。基本原则是:变量名=属性+类型+对象描述。匈牙利命名法源于微软,然而却被很多人以讹传讹的使用。而现在即使是微软也不再推荐使用匈牙利命名法。历来对匈牙利命名法的一大诟病,就是导致了变量名难以阅读,这和本规范的指导思想也有冲突,所以本规范特意强调,变量命名不应采用匈牙利命名法,而应该想法使变量名为一个有意义的词或词组,方便代码的阅读。

变量命名需要说明的是变量的含义,而不是变量的类型。在变量命名前增加类型说明,反而降低了变量的可读性;更麻烦的问题是,如果修改了变量的类型定义,那么所有使用该变量的地方都需要修改。

13、使用名词或者形容词+名词方式命名变量

14、函数命名应以函数要执行的动作命名,一般采用动词或者动词+名词的结构

正确示例:找到当前进程的当前目录:

DWORD GetCurrentDirectory( DWORD BufferLength, LPTSTR Buffer );

15、函数指针除了前缀,其他按照函数的命名规则命名

16、对于数值或者字符串等等常量的定义,建议采用全大写字母,单词之间加下划线“_”的方式命名(枚举同样建议使用此方式定义)

正确示例:

#define PI_ROUNDED 3.14

17、除了头文件或编译开关等特殊标识定义,宏定义不能使用下划线“_”开头和结尾

一般来说,‟_‟开头、结尾的宏都是一些内部的定义,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 fol lowedby an uppercase letter ora second underscore.

4、变量

1、一个变量只有一个功能,不能把一个变量用作多种用途

一个变量只用来表示一个特定功能,不能把一个变量作多种用途,即同一变量取值不同时,其代表的意义也不同。

错误示例:具有两种功能的反例

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;

}

2、结构功能单一,不要设计面面俱到的数据结构

相关的一组信息才是构成一个结构体的基础,结构的定义应该可以明确的描述一个对象,而不是一组相关性不强的数据的集合。设计结构时应力争使结构代表一种现实事务的抽象,而不是同时代表多种。结构中的各元素应代表同一事务的不同侧面,而不应把描述没有关系或关系很弱的不同事务的元素放到同一结构中。

错误示例:如下结构不太清晰、合理。

typedef struct STUDENT_STRU

{

unsigned char name[32]; /* student’s name */

unsigned char age; /* student’s age */

unsigned char sex; /* student’s sex, as follows */

/* 0 - FEMALE; 1 - MALE */

unsigned char teacher_name[32]; /* the student teacher’s 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]; /* student’s name */

unsigned char age; /* student’s age */

unsigned char sex; /* student’s sex, as follows */

/* 0 - FEMALE; 1 - MALE */

unsigned int teacher_ind; /* his teacher index */

} STUDENT;

3、不用或者少用全局变量

单个文件内部可以使用static的全局变量,可以将其理解为类的私有成员变量。

全局变量应该是模块的私有数据,不能作用对外的接口使用,使用static类型定义,可以有效防止外部文件的非正常访问,建议定义一个STATIC宏,在调试阶段,将STATIC定义为static,版本发布时,改为空,以便于后续的打补丁等操作。

4、防止局部变量与全局变量同名

尽管局部变量和全局变量的作用域不同而不会发生语法错误,但容易使人误解。

5、通讯过程中使用的结构,必须注意字节序

通讯报文中,字节序是一个重要的问题,我司设备使用的CPU类型复杂多样,大小端、32位/64位的处理器也都有,如果结构会在报文交互过程中使用,必须考虑字节序问题。由于位域在不同字节序下,表现看起来差别更大,所以更需要注意对于这种跨平台的交互,数据成员发送前,都应该进行主机序到网络序的转换;接收时,也必须进行网络序到主机序的转换。

6、严禁使用未经初始化的变量作为右值

在首次使用前初始化变量,初始化的地方离使用的地方越近越好。

7、构造仅有一个模块或函数可以修改、创建,而其余有关模块或函数只访问的全局变量,防止多个不同模块或函数都可以修改、创建同一全局变量的现象

降低全局变量耦合度。

8、使用面向接口编程思想,通过 API 访问数据:如果本模块的数据需要对外部模块开放 ,应提供接口函数来设置、获取,同时注意全局数据的访问互斥

避免直接暴露内部数据给外部模型使用,是防止模块间耦合最简单有效的方法。定义的接口应该有比较明确的意义,比如一个风扇管理功能模块,有自动和手动工作模式,那么设置、查询工作模块就可以定义接口为SetFanWorkMode,GetFanWorkMode;查询转速就可以定义为GetFanSpeed;风扇支持节能功能开关,可以定义EnabletFanSavePower等。

9、明确全局变量的初始化顺序,避免跨模块的初始化依赖

系统启动阶段,使用全局变量前,要考虑到该全局变量在什么时候初始化,使用全局变量和初始化全局变量,两者之间的时序关系,谁先谁后,一定要分析清楚,不然后果往往是低级而又灾难性的。

10、尽量减少没有必要的数据类型默认转换与强制转换

当进行数据类型强制转换时,其数据的意义、转换后的取值等都有可能发生变化,而这些细节若考虑不周,就很有可能留下隐患。

错误示例:如下赋值,多数编译器不产生告警,但值的含义还是稍有变化。

char ch;

unsigned short int exam;

ch = -1;

exam = ch; // 编译器不产生告警,此时exam为0xFFFF。

5、宏、常量

1、用宏定义表达式时,要使用完备的括号

因为宏只是简单的代码替换,不会像函数一样先将参数计算后,再传递。

错误示例:如下定义的宏都存在一定的风险

#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))

这是因为:如果定义 #define RECTANGLE_AREA(a, b) a * b 或 #define RECTANGLE_AREA(a, b) (a * b)则 c/RECTANGLE_AREA(a, b) 将扩展成 c/a * b , c 与 b 本应该是除法运算,结果变成了乘法运算,造成错误。

如果定义 #define RECTANGLE_AREA(a, b) (a * b)则 RECTANGLE_AREA(c + d, e + f) 将扩展成: (c + d * e + f), d 与 e 先运算,造成错误。

2、将宏所定义的多条表达式放在大括号中

3、使用宏时,不允许参数发生变化

错误示例:

#define SQUARE(a) ((a) * (a))

int a = 5;

int b;

b = SQUARE(a++); // 结果:a = 7,即执行了两次增。

正确示例:

b = SQUARE(a);

a++; // 结果:a = 6,即只执行了一次增。

同时也建议即使函数调用,也不要在参数中做变量变化操作,因为可能引用的接口函数,在某个版本升级后,变成了一个兼容老版本所做的一个宏,结果可能不可预知。

4、不允许直接使用魔鬼数字

使用魔鬼数字的弊端:代码难以理解;如果一个有含义的数字多处使用,一旦需要修改这个数值,代价惨重。

使用明确的物理状态或物理意义的名称能增加信息,并能提供单一的维护点。

解决途径:对于局部使用的唯一含义的魔鬼数字,可以在代码周围增加说明注释,也可以定义局部const变量,变量命名自注释。对于广泛使用的数字,必须定义const全局变量/宏;同样变量/宏命名应是自注释的。0作为一个特殊的数字,作为一般默认值使用没有歧义时,不用特别定义。

5、除非必要,应尽可能使用函数代替宏

宏对比函数,有一些明显的缺点:

  • 宏缺乏类型检查,不如函数调用检查严格;
  • 宏展开可能会产生意想不到的副作用,如#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: -1

FUNC : max of a and b is: 2

6、常量建议使用 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”;

延伸阅读材料:关于const和指针的使用,这里摘录两段ISO/IEC 9899(俗称C99)的描述:

img

7、宏定义中尽量不使用 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) /此时如果pMem2==NULL_PTR,则pMem1未释放函数就返回了,造成内存泄漏。/

所以说,类似于CHECK_AND_RETURN这些宏,虽然能使代码简洁,但是隐患很大,使用须谨慎。

6、表达式

1、表达式的值在标准所允许的任何运算次序下都应该是相同的

2、函数调用不要作为另一个函数的参数使用,否则对于代码的调试、阅读都不利

错误示例:如下代码不合理,仅用于说明当函数作为参数时,由于参数压栈次数不是代码可以控制的,可能造成未知的输出:

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());

}

上面的代码,使用断点调试起来也比较麻烦,阅读起来也不舒服,所以不要为了节约代码行,而写这种代码。

3、赋值语句不要写在 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);

}

作用函数参数来使用,参数的压栈顺序不同可能导致结果未知。

4、用括号明确表达式的操作顺序,避免过分依赖默认优先级

使用括号强调所使用的操作符,防止因默认的优先级与设计思想不符而导致程序出错;同时使得代码更为清晰可读,然而过多的括号会分散代码使其降低了可读性。

5、赋值操作符不能使用在产生布尔值的表达式上

示例:

x = y;

if (x != 0)

{

foo ();

}

不能写成:

if (( x = y ) != 0)

{

foo ();

}

或者更坏的:

if (x = y)

{

foo ();

}

7、注释

1、优秀的代码可 以自我解释,不通过注释即可轻易读懂

优秀的代码不写注释也可轻易读懂,注释无法把糟糕的代码变好,需要很多注释来解释的代码往往存在坏味道,需要重构。

错误示例:注释不能消除代码的坏味道:

/* 判断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;

/* 遍历中没有发现整除的情况,返回*/

else

return 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;

}

2、注释的内容要清楚、明了,含义准确,防止注释二义性

有歧义的注释反而会导致维护者更难看懂代码,正如带两块表反而不知道准确时间。

3、在代码的功能、意图层次上进行注释,即注释解释 代码难以直接表达的意图 , 而不是重复描述代码

注释的目的是解释代码的目的、功能和采用的方法,提供代码以外的信息,帮助读者理解代码,防止没必要的重复注释信息。对于实现代码中巧妙的、晦涩的、有趣的、重要的地方加以注释。注释不是为了名词解释(what),而是说明用途(why)。

4、修改代码时,维护代码周边的所有注释,以保证注释与代码的一致性,不再有用的注释要删除

不要将无用的代码留在注释中,随时可以从源代码配置库中找回代码;即使只是想暂时排除代码,也要留个标注,不然可能会忘记处理它。

5、文件头部应进行注释,注释必须列出:版权说明、版本号、生成日期、作者姓名、工号、内容、功能说明、与其它文件的关系、修改日志等,头文件的注释中还应有函数功能简要说明

正确示例:下面这段头文件的头注释比较标准,当然,并不局限于此格式,但上述信息建议要包含在内。

img

6、函数声明处注释描述函数功能、性能及用法,包括输入和输出参数、函数返回值、可重入的要求等;定义处详细描述函数功能和实现要点,如实现的简要步骤、实现的理由、 设计约束等

重要的、复杂的函数,提供外部使用的接口函数应编写详细的注释。

7、全局变量要有较详细的注释,包括对其功能、取值范围以及存取时注意事项等的说明

正确示例:

/* 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;

8、注释应放在其代码上方相邻位置或右方,不可放在下面,如放于上方则需与其上面的代码用空行隔开,且与下方代码缩进相同

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

}

}

return TRUE;

}

2、注释的内容要清楚、明了,含义准确,防止注释二义性

有歧义的注释反而会导致维护者更难看懂代码,正如带两块表反而不知道准确时间。

3、在代码的功能、意图层次上进行注释,即注释解释 代码难以直接表达的意图 , 而不是重复描述代码

注释的目的是解释代码的目的、功能和采用的方法,提供代码以外的信息,帮助读者理解代码,防止没必要的重复注释信息。对于实现代码中巧妙的、晦涩的、有趣的、重要的地方加以注释。注释不是为了名词解释(what),而是说明用途(why)。

4、修改代码时,维护代码周边的所有注释,以保证注释与代码的一致性,不再有用的注释要删除

不要将无用的代码留在注释中,随时可以从源代码配置库中找回代码;即使只是想暂时排除代码,也要留个标注,不然可能会忘记处理它。

5、文件头部应进行注释,注释必须列出:版权说明、版本号、生成日期、作者姓名、工号、内容、功能说明、与其它文件的关系、修改日志等,头文件的注释中还应有函数功能简要说明

正确示例:下面这段头文件的头注释比较标准,当然,并不局限于此格式,但上述信息建议要包含在内。

img

6、函数声明处注释描述函数功能、性能及用法,包括输入和输出参数、函数返回值、可重入的要求等;定义处详细描述函数功能和实现要点,如实现的简要步骤、实现的理由、 设计约束等

重要的、复杂的函数,提供外部使用的接口函数应编写详细的注释。

7、全局变量要有较详细的注释,包括对其功能、取值范围以及存取时注意事项等的说明

正确示例:

/* 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;

8、注释应放在其代码上方相邻位置或右方,不可放在下面,如放于上方则需与其上面的代码用空行隔开,且与下方代码缩进相同

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-jiz3ICMG-1713200632831)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/2401_84267856/article/details/137801246

智能推荐

python opencv resize函数_python opencv 等比例调整(缩放)图片分辨率大小代码 cv2.resize()...-程序员宅基地

文章浏览阅读1.3k次。# -*- coding: utf-8 -*-"""@File : 200113_等比例调整图像分辨率大小.py@Time : 2020/1/13 13:38@Author : Dontla@Email : [email protected]@Software: PyCharm"""import cv2def img_resize(image):height, width = image...._opencv小图等比例缩放

【OFDM、OOK、PPM、QAM的BER仿真】绘制不同调制方案的误码率曲线研究(Matlab代码实现)-程序员宅基地

文章浏览阅读42次。对于这些调制技术的误码率(BER)研究是非常重要的,因为它们可以帮助我们了解在不同信道条件下系统的性能表现。通过以上步骤,您可以进行OFDM、OOK、PPM和QAM的误码率仿真研究,并绘制它们的误码率曲线,以便更好地了解它们在不同信道条件下的性能特点。针对这些调制技术的BER研究是非常重要的,可以帮助我们更好地了解这些技术在不同信道条件下的性能表现,从而指导系统设计和优化。6. 分析结果:根据误码率曲线的比较,分析每种调制方案在不同信噪比条件下的性能,包括其容忍的信道条件和适用的应用场景。_ber仿真

【已解决】Vue的Element框架,日期组件(el-date-picker)的@change事件,不会触发。_el-date-picker @change不触发-程序员宅基地

文章浏览阅读2.5w次,点赞3次,收藏3次。1、场景照抄官方的实例,绑定了 myData.Age 这个值。实际选择某个日期后,从 vuetool(开发工具)看,值已经更新了,但视图未更新。2、尝试绑定另一个值: myData,可以正常的触发 @change 方法。可能是:值绑定到子对象时,组件没有侦测到。3、解决使用 @blur 代替 @change 方法。再判断下 “值有没有更新” 即可。如有更好的方法,欢迎评论!..._el-date-picker @change不触发

PCL学习:滤波—Projectlnliers投影滤波_projectinliers-程序员宅基地

文章浏览阅读1.5k次,点赞2次,收藏8次。Projectlnliersclass pcl: : Projectlnliers< PointT >类 Projectlnliers 使用一个模型和一组的内点的索引,将内点投影到模型形成新的一个独立点云。关键成员函数 void setModelType(int model) 通过用户给定的参数设置使用的模型类型 ,参数 Model 为模型类型(见 mo..._projectinliers

未处理System.BadImageFormatException”类型的未经处理的异常在 xxxxxxx.exe 中发生_“system.badimageformatexception”类型的未经处理的异常在 未知模块。 -程序员宅基地

文章浏览阅读2.4k次。“System.BadImageFormatException”类型的未经处理的异常在 xxxx.exe 中发生其他信息: 未能加载文件或程序集“xxxxxxx, Version=xxxxxx,xxxxxxx”或它的某一个依赖项。试图加载格式不正确的程序。此原因是由于 ” 目标程序的目标平台与 依赖项的目标编译平台不一致导致,把所有的项目都修改到同一目标平台下(X86、X64或AnyCPU)进行编译,一般即可解决问题“。若果以上方式不能解决,可采用如下方式:右键选择配置管理器,在这里修改平台。_“system.badimageformatexception”类型的未经处理的异常在 未知模块。 中发生

PC移植安卓---2018/04/26_电脑软件移植安卓-程序员宅基地

文章浏览阅读2.4k次。记录一下碰到的问题:1.Assetbundle加载问题: 原PC打包后的AssetBundle导入安卓工程后,加载会出问题。同时工程打包APK时,StreamingAssets中不能有中文。解决方案: (1).加入PinYinConvert类,用于将中文转换为拼音(多音字可能会出错,例如空调转换为KongDiao||阿拉伯数字不支持,如Ⅰ、Ⅱ、Ⅲ、Ⅳ(IIII)、Ⅴ、Ⅵ、Ⅶ、Ⅷ、Ⅸ、Ⅹ..._电脑软件移植安卓

随便推点

聊聊线程之run方法_start 是同步还是异步-程序员宅基地

文章浏览阅读2.4k次。话不多说参考书籍 汪文君补充知识:start是异步,run是同步,start的执行会经过JNI方法然后被任务执行调度器告知给系统内核分配时间片进行创建线程并执行,而直接调用run不经过本地方法就是普通对象执行实例方法。什么是线程?1.现在几乎百分之百的操作系统都支持多任务的执行,对计算机来说每一个人物就是一个进程(Process),在每一个进程内部至少要有一个线程实在运行中,有时线..._start 是同步还是异步

制作非缘勿扰页面特效----JQuery_单击标题“非缘勿扰”,<dd>元素中有id属性的<span>的文本(主演、导演、标签、剧情-程序员宅基地

文章浏览阅读5.3k次,点赞9次,收藏34次。我主要用了层次选择器和属性选择器可以随意选择,方便简单为主大体CSS格式 大家自行构造网页主体<body> <div class='main' > <div class='left'> <img src="images/pic.gif" /> <br/><br/> <img src="images/col.gif" alt="收藏本片"/&_单击标题“非缘勿扰”,元素中有id属性的的文本(主演、导演、标签、剧情

有了这6款浏览器插件,浏览器居然“活了”?!媳妇儿直呼“大开眼界”_浏览器插件助手-程序员宅基地

文章浏览阅读901次,点赞20次,收藏23次。浏览器是每台电脑的必装软件,去浏览器搜索资源和信息已经成为我们的日常,我媳妇儿原本也以为浏览器就是上网冲浪而已,哪有那么强大,但经过我的演示之后她惊呆了,直接给我竖起大拇指道:“原来浏览器还能这么用?大开眼界!今天来给大家介绍几款实用的浏览器插件,学会之后让你的浏览器“活过来”!_浏览器插件助手

NumPy科学数学库_数学中常用的环境有numpy-程序员宅基地

文章浏览阅读101次。NumPy是Python中最常用的科学数学计算库之一,它提供了高效的多维数组对象以及对这些数组进行操作的函数NumPy的核心是ndarray(N-dimensional array)对象,它是一个用于存储同类型数据的多维数组Numpy通常与SciPy(Scientific Python)和 Matplotlib(绘图库)一起使用,用于替代MatLabSciPy是一个开源的Python算法库和数学工具包;Matplotlib是Python语言及其Numpy的可视化操作界面'''_数学中常用的环境有numpy

dind(docker in docker)学习-程序员宅基地

文章浏览阅读1.1w次。docker in docker说白了,就是在docker容器内启动一个docker daemon,对外提供服务。优点在于:镜像和容器都在一个隔离的环境,保持操作者的干净环境。想到了再补充 :)一:低版本启动及访问启动1.12.6-dinddocker run --privileged -d --name mydocker docker:1.12.6-dind在其他容器访问d..._dind

推荐文章

热门文章

相关标签