【C/C++】C语言编程规范

C语言编码规范

参考Linux kernel代码规范,社区对于C语言编码做如下要求:

缩进

● 使用Tab作为行首缩进,而不是空格。Tab Size设为4字符

● switch语句中,case不缩进

cpp 复制代码
switch (var) {
case 0:
	
	break;
case 1:
	
	break;
default:
	
	break;
}

换行

● 每行不超过80字符

● 超过80字符时需要换行

以函数声明为例,推荐的换行方式是次行首字母与函数左括号对齐。

cpp 复制代码
static const struct uk_thread *schedprio_idle_thread(struct uk_sched *s,
													 unsigned int proc_id);

● 每行末尾不能有空白字符

● 只有换行会严重影响代码可读性时,才允许单行超过80个字符。例如banner打印等场景

空格

● C语言关键字(if、switch、case、for、do、while、return、void等)后需要添加空格

● 逗号如果不在行尾,后面需要添加空格

● 不要在圆括号周围添加空格

cpp 复制代码
if ( condition ) {
	
}


if (condition) {
	
}

● 对于指针类型定义,'*'靠近变量名、函数名

cpp 复制代码
char* name;


char *name;
char *func(int *arg);

花括号

● 对于function,将花括号("{"、"}")放置在下一行首

cpp 复制代码
void function(int arg)
{
	
}

● 除function外,将左花括号("{")放置在当前代码行,右花括号("}")另起一行。右花括号后可跟随条件语句。

cpp 复制代码
if (x == y) {
	
} else if (x > y) {
	
} else {
	
}
do {
	body of do-loop
} while (condition);

● 为降低长线维护发生逻辑错误的概率,对于条件判断等逻辑,即时是单行代码也请使用大括号

cpp 复制代码
if (x == y) {
	x++;
}

while (condition1) {
	if (condition2) {
		x++;
	} else {
		y++;
	}
}

● 为了保证代码可读性,请尽量减少花括号的嵌套层数。

cpp 复制代码
if (condition1) {
	if (condition2) {
		
	}
}


if (condition1 && condition2) {
	
}

使用typedef的场景

● 提升跨平台兼容性

● 需要隐藏具体实现

● 通过别名可以直观地识别类型信息

cpp 复制代码
typedef unsigned long int uint64_t;

typedef __u32 __lcpuid;

头文件

● 为了避免重复导入头文件,需要使用include guard宏,命名方式为__TN_{filename}H_

cpp 复制代码
#ifndef __TN_SCHEDPRIO_H__
#define __TN_SCHEDPRIO_H__

#endif

● 尽量避免C代码和汇编代码引用相同头文件。如果不得不这么做,使用__ASSEMBLY__进行区分

cpp 复制代码
#if !__ASSEMBLY__

#endif

#if __ASSEMBLY__

#endif

注释

● 采用多行注释风格

cpp 复制代码
while (condition) {
	...
}


while (condition) {
	...
}

● 使用Doxgen风格的函数注释,注释中行首缩进使用空格

cpp 复制代码
struct timer *timer_create(
	systick_t init_tick,
	void (*timeout_func)(void *parameter),
	void *parameter,
	unsigned long flag);

预处理指令注释

● 当#ifdef、#else、#endif等条件预处理指令跨越很长的代码段时,往往可读性很差。需要在分支结束处通过注释进行条件说明,注释内容为前一个分支处理的条件。

cpp 复制代码
#ifdef CONFIG_HAVE_SMP

#else 

#endif

● 对于#if、#ifdef、#elif等预处理指令,由于关键字后就是判断条件,不需要添加注释

● 预处理指令跨度较短,可以直观理解代码逻辑时,不需要添加注释

命名

● 全局变量、全局可见函数命名需要满足自描述性,不要使用不可识别的缩写

cpp 复制代码
struct thread curthr;
struct thread *curthr();


struct thread current_thread;
struct thread *current_thread();

● 采用蛇形命名,多个单词使用下划线('_')连接

cpp 复制代码
void some_function(void);
int some_var;
#define SOME_MACRO 0

宏定义

● 采用全小写字母命名函数(形式的宏),采用全大写字母命名常量

● 用于操作寄存器的函数形式的宏,可以采用全大写字母命名

● 如果函数形式的宏包含未使用的参数,请使用static inline函数,不要使用宏

● 多行语句需要使用do...while

cpp 复制代码
#define macrofun(a, b, c)		\
	do {						\
		if ((a) == 5)			\
		do_this((b), (c));		\
	} while (0)

● 不要在宏中使用return,这会导致调用该宏的函数返回

● 使用表达式定义常量时,必须用括号括起来,避免在使用时由于操作符优先级导致的异常结果;同样,对于函数形式的宏,每个参数在函数体中都要用括号括起来

cpp 复制代码
#define SOME_CONSTANT 0x80000000
#define ANOTHER_CONSTANT (0xFF | SOME_CONSTANT)

#define BASE_ADDR 0x8000
#define SOME_REGISTER(x) (BASE_ADDR + (x))

● 宏中定义临时变量时,要考虑作用域。使用常见的临时变量名,在宏展开时可能与同作用域的其他变量冲突

cpp 复制代码
#define some_function()		\
	do {
		
		int ret;

		

		
		(ret);
	} while (0)


#define some_function()		\
	do {
		
		int _some_function_ret;

		
		(_some_function_ret);
	} while (0)

函数实现

● 尽量保持函数体短小精炼,一个函数实现单一功能

● 复杂度较高的函数尽量拆分成多个子函数实现,以提升可读性和可维护性

● 如果函数中使用的临时变量超过10个,它的功能可能过于复杂了,需要考虑如何拆分

● 函数体后需要保留一行空行

cpp 复制代码
void some_function(void)
{
	
}

● 变量声明和功能代码之间需要保留一行空行

cpp 复制代码
void some_function(void)
{
	int some_var_i;
	char some_var_c;

	if (condition1) {
		some_var_i++;
	}
	
}

● 如果一个函数需要被其他微库调用,需要将函数名写入到所在微库的exportsyms.uk文件中。例如tenon/lib/tnschedprio/exportsyms.uk

函数返回值

tenon目前没有提供bool型,当函数返回一个整型值,用于表示函数功能是否异常时,遵循以下规则:

● 操作、执行、命令类函数

○ 返回 0 值代表成功,非0 值代表错误码

● 判断类函数

○ 返回 0 值代表false,1 值代表true

cpp 复制代码
int is_cpu();


int configure_gic_distriutor(void *dtb);

函数退出处理和GOTO使用

● 可以使用GOTO统一处理函数的退出逻辑(错误处理、资源回收等),但需要满足:

○ 使用GOTO可以减少条件分支,或者减少代码嵌套层数

○ 函数有多个退出点,使用GOTO将退出逻辑汇总在一处,可以减少重复代码,同时避免后续维护过程中多点修改出现遗漏

● 使用GOTO时,标签名需要有实际意义,例如说明后续代码的意图,说明走到该分支的原因等。避免使用err1、err2等无意义标签

cpp 复制代码
int testfunc(void)
{
	void *a, *b;
	int rc = 0;

	a = malloc(...);
	if (unlikely(!a)) {
		
		return -ENOMEM;
	}

	b = malloc(...);
	if (unlikely(!b)) {
		rc = -ENOMEM;
		goto out_free_a;
	}

	...

	if (condition) {
		rc = 1;
		goto out_free_b;
	}

out_free_b:
	free(b);
out_free_a:
	free(a);
	return rc;
}

● 其他场景请尽量避免使用GOTO

汇编

● 如果使用C代码能够实现相同功能,尽量不要使用汇编代码

● 指令和操作数之间使用Tab

● 存在多行汇编指令时,每条指令一行,"\n\t"结尾

● 使用asm volatile替代__asm__ volatile

cpp 复制代码
__asm__ __volatile__ (
	"instr	op, op\n\t"
	"instr2	op, op"
	:::);


asm volatile (
	"instr	op, op\n\t"
	"instr2	op, op"
	:::);

● 对于较长的内联汇编代码,尽量添加足够的注释,便于开发者理解代码功能

后续继续学习其他的规范,进行分享。

相关推荐
mlidongfeng11 分钟前
[AI][C++26] SIMD 编程模型思考
开发语言·c++·人工智能
梓䈑11 分钟前
【用 Vibe Coding 实现的 C++17 在线判题系统】OpenCode 入门指南:从环境搭建到上下文管理
c++·ai编程
j7~11 分钟前
【Linux】二十七.线程篇四《Linux多线程编程:线程互斥(互斥量的底层到封装)、线程安全和冲入、死锁》---详解
linux·开发语言·c++·线程安全·死锁·线程互斥·重入
啦啦啦啦啦zzzz18 分钟前
贪心算法和动态规划
c++·算法·贪心算法·动态规划
刘名喜21 分钟前
第09篇-协程基础-Kotlin异步编程
开发语言·kotlin·springboot
其实防守也摸鱼26 分钟前
HackBar 工具完全指南:信息探测、漏洞验证与安全测试实战
开发语言·人工智能·学习·安全·网络安全·安全威胁分析·安全性测试
我不是懒洋洋35 分钟前
从零实现一个分布式数据集成:Airbyte的核心设计
c++
会博通·代码搬运工39 分钟前
会博通API对接实战:工程企业文档分布式采集系统的技术实现与Python SDK详解
开发语言·分布式·python·线性代数·矩阵·架构·电子档案合规
用户05101225729641 分钟前
DAY 5-智能指针与 C++ 内存管理
c++·面试
(Charon)1 小时前
【C++】手写 MySQL 连接池(三):异步任务队列与工作线程
c语言·c++