编程修养

想几年前初学 C 语言的时候看到过 陈皓《编程修养》 中的内容,当时不以为意。

如今工作一年后无意间再次看到这篇文章,感触颇深。
发现其中的每一点言之凿凿。

于是加上一点自己的一些心得。转载之。

版权&版本

在写代码的时候添加文件头,可以利用 vimrc 自动实现这个功能:Vim设置(非常全)
在每次生成新文件的时候都会自动生成形如下面样式的文件头。

/*************************************************************************
    > File Name: test.c
    > Author: Younix
    > Mail: foreveryounix@gmail.com 
    > Created Time: 2016年10月14日 星期五 15时28分28秒
 ************************************************************************/

缩进、空格、换行、空行、对齐

同样利用 Vimrc 来实现,在 .vimrc 中添加

" 自动缩进
set autoindent
set cindent
" Tab键的宽度
set tabstop=4
" 统一缩进为4
set softtabstop=4
set shiftwidth=4
" 不要用空格代替制表符
"set noexpandtab
" 将制表符用 4 个空格替代
set ts=4
set expandtab
" 在行和段开始处使用制表符
set smarttab

更多详细的也可以参考之前那篇文章。

BTW:indent 命令也是一个好方法

注释

注释的格式应该如此写:

/*================================================================
 * 函 数 名:XXX
 * 参    数: 
 *        type name [IN] : descripts
 * 功能描述: 
 *        ..............
 * 返 回 值:成功TRUE,失败FALSE
 * 抛出异常:
 * 作    者:Younix 2016/10/14
 *
 ================================================================*/

函数的[in][out]参数

在调用某个函数前先判断一下传进来的指针是否合法!
使用断言 assert

对系统调用的返回进行判断

  1. 文件返回的文件描述符
  2. socket 返回的 socket 号
  3. malloc 返回的内存
    这些我使用 dbg.h 中的 check() 宏完成检查。
    dbg.h 是 Zed.Shaw 编写的一个比较不错的 debug 宏合集。非常好用。
#ifdef NDEBUG
#define debug(M, ...)
#else
#define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__) //牛逼
#endif
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
#define log_err(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
#define log_warn(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)

#define check(A, M, ...) if(!(A)) { log_err(M, ##__VA_ARGS__); errno=0; goto error; }
#define sentinel(M, ...)  { log_err(M, ##__VA_ARGS__); errno=0; goto error; }
#define check_mem(A) check((A), "Out of memory.")
#define check_debug(A, M, ...) if(!(A)) { debug(M, ##__VA_ARGS__); errno=0; goto error; }

下载地址:http://download.csdn.net/detail/dearsq/9653980

if 语句的错误处理

先写错误处理,再写正常逻辑

头文件中的 #ifndef

这个毋庸置疑非常重要,为了防止交叉引用

在堆上分配内存

栈上分配内存方法:

    char*
    AllocStrFromStack()
    {
        char pstr[100];
        return pstr;
    }

堆上分配内存方法:

char*
    AllocStrFromHeap(int len)
    {
        char *pstr;

        if ( len <= 0 ) return NULL;
        return ( char* ) malloc( len );
    }

栈上分配的内存在函数结束时被释放,此时返回有可能出现段错误。
堆上分配的内存在free时才被释放,在函数返回时仍然存在。

malloc 分配的内存一定要初始化;
free 后的指针一定要设置为 NULL。
内存检查工具 Purify

变量初始化

  1. malloc 后记得 memset 清零
  2. 对栈上分配的 struct 或数组进行初始化
  3. 对全局和静态变量,声明时就要初始化

h和c文件的使用

声明和实现严格分开,采用 Makefile 来管理。

另外,在 .h 中不要初始化。

出错信息的处理

我采用的是 dbg.h 中提供的方式。

常用函数和循环语句中的被计算量

GetLocalHostName(char* name)
{
    char funcName[] = "GetLocalHostName";

    sys_log( "%s begin......", funcName );
    ...
    sys_log( "%s end......", funcName );
}

如果这个函数经常被调用,那么可以把 funcName 声明为 static。

函数名和变量的命名

这个不多说,最好望文生义。

函数的传值和传指针

其实任何时候都是在传值,看似传指针也只是传的指针的副本。

void
GetVersion(char* pStr)
{
    pStr = malloc(10);
    strcpy ( pStr, "2.0" );
}
main()
{
    char* ver = NULL;
    GetVersion ( ver );
    ...
    ...
    free ( ver );
}

其实这里函数的形参 pStr 只是 ver 的副本。
因为是副本,pStr 所指向的地方和 ver 所指向的地方相同,但是如果对其取地址的话,可以看到 &pStr 和 &ver 是不同的。因为这里也只是 值 传递。

修改他人程序

删除时请使用注释

把相同或近乎相同的代码形成函数和宏

如题

表达式中的括号

为了避免误解,多加括号没有错的。

函数参数中的 const

在函数中只读的参数请使用 const。
虽然指针即使用 const 修饰后依然能改,但是编译器会报 Warning,可以引起注意。

函数的参数个数

参数太多请用结构体传参。

返回类型

不要省略

goto 语句

除了错误处理,其他情况不要用 goto。

宏定义

宏可以加快运行速度(减少函数调用的开销),但是会增加执行文件体积。
而且注意将变量()起来。

不要给宏定义加分号

static

最初了解 static 是因为全局变量。
但是他最大的作用是在于控制访问。
C 中如果一个函数或者一个全局变量 被声明为 static,那么它们将只能在这个 C 中被访问!

函数代码尺寸

保证函数功能的单一性

typedef

typedef char bool;

为常量声明宏

char name[NAME_SIZE]

|| && 语句执行顺序

注意 && 时,并不一定所有判断都会执行。

尽量用for而不是while做循环

请sizeof 类型而不是变量

不要忽略Warning

  1. 声明了未使用的变量。(虽然编译器不会编译这种变量,但还是把它从源程序中注释或是删除吧)
  2. 使用了隐晦声明的函数。(也许这个函数在别的C文件中,编译时会出现这种警告,你应该这使用之前使用extern关键字声明这个函数)
  3. 没有转换一个指针。(例如malloc返回的指针是void的,你没有把之转成你实际类型而报警,还是手动的在之前明显的转换一下吧)
  4. 类型向下转换。(例如:float f = 2.0; 这种语句是会报警告的,编译会告诉你正试图把一个double转成float,你正在阉割一个变量,你真的要这样做吗?还是在2.0后面加个f吧,不然,2.0就是一个double,而不是float了)

书写Debug版和Release版的程序

参考 dbg.h 添加调试函数。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
嵌入式C语言的自我修养主要包括以下几个方面: 1. 熟悉C语言基础知识。嵌入式C语言和普通C语言有很多相同的基础知识,比如变量、数据类型、运算符、控制语句等等。因此,在学习嵌入式C语言之前,需要先掌握好C语言的基础知识。 2. 学习嵌入式系统的硬件知识。嵌入式系统的硬件知识包括处理器架构、存储器、外围设备等等。在编写嵌入式程序时,需要考虑硬件的特性和限制,才能编写出高效、稳定的程序。 3. 掌握嵌入式系统的编程规范。嵌入式系统的编程规范和普通的软件开发有很大的不同。比如,需要注意代码的大小和效率,要避免使用动态内存分配等等。掌握嵌入式系统的编程规范可以帮助你编写出更加优秀的程序。 4. 学习嵌入式系统的操作系统。如果你要编写嵌入式系统的操作系统,就需要学习操作系统的相关知识。学习操作系统可以帮助你更好地管理系统资源,提高系统的性能和稳定性。 5. 不断实践和积累经验。在学习嵌入式C语言的过程中,需要不断实践和积累经验。可以通过参加开源项目、写一些小项目来提高自己的编程能力。 总之,嵌入式C语言的自我修养需要有一个全面的学习计划,包括掌握基础知识、学习硬件知识、掌握编程规范、学习操作系统和不断实践和积累经验等方面。只有这样才能成为一名优秀的嵌入式系统开发工程师。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值