c语言——编程规范及注意事项

编写c语言的目的

  • 根本————代码正确、可执行
  • 提升————代码可读性高(易读、易懂、注释明确、符合规范)、高效
  • 完美————健壮、可移植

第一步的根本自然不必多说;代码写完之后,在测试的时候难免要修改,而且大项目的开发一般需要多人协作,因此除了个人要保证自己代码可以被他人看懂之外,还要保证自己代码规范可以与他人完美组合,没有冲突,这就需要有统一的规范——一般把一些默认的规范作为标准。在这个基础上,代码可以协作执行了,考虑代码效率问题,完美时间复杂度与空间复杂度的优化;最后,考虑到操作系统平台的差异,需要提升代码移植性,代码健壮性。使代码可以跨平台移植,且代码可以保证长久的健壮,不会被丢弃,少补丁。

现在,来分析一下c中常见的编程错误和优秀编码规范吧

1、注意=与==的区别——前者为赋值,后者为判断

if(100==a[i])与if(a[i]==100)前者较好,可以避免把==写成=造成的错误

2、&&与||的操作

与操作:对于&&操作,例如if((a>1) && (b++)),如果a>1成立,则执行b++;但是如果a>1不成立,后面的不会再执行

或操作:对于||操作,例如if((a>1) || (b++)),如果a>1不成立,则执行b++;但是如果a>1成立,后面的不会再执行

第一个条件的判定对于第二个条件是否执行影响巨大,可能会间接影响全局,因此使用时注意

例如:

a=1;b=3; if((a>1) && (b++)) c=5;                 结果为 a=1 b=3

a=2;b=3; if((a>1) && (b++)) c=5;                 结果为 a=2 b=4

3、这个不是陷阱,是一个在c陷阱与缺陷里面十分恐怖的表达式——(*(void(*)())0x8000)();

看着脑袋就大了,这个表达式是执行0x8000所在地址的程序,现在我们来分析一下(力争逐步分析):

第一步——什么是指向函数的指针,例如int (*pt)();这个函数就是指向函数的指针,pt指向这个函数的入口地址(函数是在内存之中的,pt指向函数的入口);那么如何调用函数呢,(*pt)();表示从pt指向的地址开始执行函数

第二步——代码从0x8000开始执行,使用(*0)()不就ok了吗?不是如此,因为*后面必须跟着一个指针;而且这个指针必须是函数指针;

首先定义一个函数指针 void(*pt)();

然后强制转换赋值,把0强制转换为函数指针 pt =(void(*)()) 0;

最后执行操作 (*pt)();

将三个操作合并成一个,即为 (*(void(*)())0)();

4、switch操作——注意break在其中的作用。break与continue的区分

5、结构使用时,如果结构为指针,使用”->”;否则使用”.”

6、malloc分配内存,必须及时释放,否则会造成内存泄漏(最好加上限制,保证不越界)

7、数组与指针

数组:

  • 仅支持一维数组,但数组的元素可是任意类型的数据。(数据可以为数组,保证了多维数组的实现)
  • 数组的大小必须在编译初期作为常数指定。(需要分配空间进行初始化)
  • 数组的索引值从0开始。
  • 仅能确定数组大小,以及数组下标为0的元素指针。

指针的特点:

  • 指针本身的大小都是一样的,仅与机器位宽有关(32位系统就是32/8=4字节;64位系统就是64/8=8字节)
  • 任何指针都是指向某种类型的变量(指针是可变的,除非加上const的限制)
  • 一个指针只能指向一个地址,一个地址可以被任意多个指针指向

8、宏定义的使用,避免冲突

#ifndef NUM

#define NUM 100

#endif

9、尽量不用全局变量,不得已使用的话,一定用g_开头标示出来;

——宏定义 务必全用大写,不要用’_’开头;——'_'开头的是c内部定义的,避免冲突

——枚举务必全用大写;

目的是为了尽快区分,避免代码混乱和造成冲突

10、一个变量只有一个功能,禁止重复使用;

例如:int ret;...;ret = result1();…; ret = result2();…;return0;

              int ret1,ret2;...;ret1 = result1();…;ret2 = result2();…;return 0;

即使对操作无任何影响,但是在比较复杂的代码中前者会造成代码可读性下降

在不同的类型变量操作中,特别注意默认类型转换和强制类型转换造成的数据精度丢失

建议所有的常量使用const全局变量,而不是用宏定义——(这个建议是为了反编译,假如代码出错了,而且从机器指令中发现错误的地址,此时需要反编译得到汇编语言,来查询地址操作,定义为const反编译的代码容易理解)

11、函数的参数尽量不要超过四个

因为一个进程的函数执行最多分配4个寄存器来存储参数,多的存到栈中,栈中数据的获取比寄存器慢的多~~~如此要求只是为了提高代码的执行质量

——函数的参数尽量采用整型长度

因为对于32位系统,int为4字节(4*8=32位);对于64位系统,int为8字节(8*8=64位)。指针与int总是保持一致。传递int与指针可以保证寄存器可以完全的存储(不需要做其他的操作),加快处理速度。因此,最好使用int或指针传递。

12、int a=0x12345678;char *p;p=&a;      得到*p = 120

这里定义了一个整型数据a,然后把它的地址给了p,

解析:a是一个整型,有四个字节,低位在前,高位在后存储方式,按顺序——78(字节1)、56(字节2)、34(字节3)、12(字节4)

现在q就是78(字节1))的地址,输出为7*16+8=120。不同的系统可能不同,也可能位高位在前,低位在后存储方式,此时输出的结果为1*16+2=18

13、结构struct的大小

struct point{

char b;

char c;

double d;

int a;};

使用sizeo(point)结果为24; 如果把struct中的int a与double d换个位置,使用sizeo(point)结果为16。

原因:

struct内部以字节最大的数据为基准,进行匹配,就如上面的double最大,为8字节,所以struct就以8字节为最小单位,因为之前定义的不足8字节(两个char为2字节),所以看作8字节,在double之后的int也被看作8字节,结果为24。

调换位置之后,double变为最后一个,之前的三个加起来不足8字节,因此结果为16

14、关于getchar()一类函数的问题

Int a;

a=getchar();

需要注意的是getchar();返回值为int(因为可能为EOF),所以使用int而不是char来接收结果(EOF为-1,char表示不了)

15、在函数中返回指针

理解之后——举例一个函数操作

char* fun1(){

char a[10] =“kkkkkkkk”;

char *p = a;

return p;}

如果执行这个函数  fun1,在栈区分配空间,p为指向栈区的指针。因为函数执行完之后,栈区会被自动回收,因此返回p无法找到“kkkkkkkk”这个字串。

16、<<与>>的注意

按位操作运算符:

<<左移

>>右移

左移就是带着符号位左移,没有区别(高位移出,低位补0)

右移是与unsigned有关的:

1、假如为unsigned的无符号定义,则直接右移,高位补0

2、如果不是unsigned,最高位符号位不动,次高位根据符号位补充。即符号位为1,则补1;符号位为0,则补0

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言编程注意事项 1. 每个程序中一定包含main()函数, 尽管C语言中对函数命名没有限制。 2. printf函数永远不会自动换行, 只能用\n来实现, 回车键进行的换行在编译中会出现错误信息。 3. 在vs2008等平台中编译、测试要加 system("pause"); 来暂停dos自动退出引起的printf无法显示。 4. 所有自定义变量必须声明才能使用。 5. 每行一般只写一条语句, 在运算符两边加一个空格, 便于阅读。 6. 整数除法将会自动舍位, 不进行四舍五入的操作。 7. for(初始化部分;条件部分;增长部分) 比while 更适用于初始化和增长步长都是单条语句的情况。 8. 使用 #define 名字替换文本对部分"幻数" 赋予意义便于阅读 #define结尾无需;号来结束。 9. EOF(end of file)表示没有字符输入时定义在stdio.h 头文件中 EOF不等于\n 换行等。 10. 由于!= 的优先级大于 = ,因此如果对判断中存在变量赋值时 应对赋值加() 例如: while((c = getchar()) != EOF)。 11. getchar() 用于用户输入直至键入回车键。 12. 变量名以字母和数字组成, (下划线"_"被默认为字符, 以下划线为首写字母的为库类变量名), 变量常以小写字母开头,内部变量名前31位有效, 外部变量名至少前6位保持唯一性。 13.在C语言中是区分字母大小写的。 14. 一个字符常量为一个整数, 用''单引号括起来。例如: '0' 为48, 它与0没有任何关系。 15. ANSI C语言的转义符: \a 响铃符; \b 回退符; \f 换页符; \n 换行符; \r 回车符; \t 横向制表符 ; \v 纵向制表符; \\ 反斜杠; \? 问号; \' 单引号; \" 双引号; \ooo 八进制数; \xhh 十六进制数; '\0' 表示0, 即(null)。 16. 'x'与"x"的区别: 'x'表示一个整数, 字母x在其字符集中对应的数值, "x"表示包含一个字符x 以及一个结束符'\0'。 17. const在声明变量中起限制作用, 该限定变量的值不能被修改。 18. %运算符不能应用于float或double类型。 19. char类型转换为int型时, 因为无法判断它是signed还是unsigned,这样其结果有可能为负数, 所以转换时尽量指定signed和unsigned限制符。 20. ++i与i++ 的不同之处: ++i是先 +1再使用i, i++ 是先使用i再 +1。 21. 三元运算符"?:" 第一个表达式的括号不是必须的, 但是由于三元表达式的优先级非常低, 因此我们还是将第一个表达式用()括起来以便于阅读和理解。 22. C语言中可以使用递归 (即函数调用自身函数), 这样做并不节省储存空间也不加快执行速度, 只是使程序紧凑便于理解。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值