C语言深度解析(二)

 4.变量命名规则
        (1)一般规则:
             a:命名应当直观且可以拼读,可望文知意,便于记忆和阅读。
             b:命名的长度应当符合“min-length && max-information”原则。
             c:当标示符由多个词组成时,每个词的第一个字母大写,其余全部小写。
             d:尽量避免名字中出现数字编号,如Value1,Value2等,除非逻辑上的确需要编号,比如驱动开发是为引脚命名,飞编号名字反而不好。
             e:对在多个文件之间共同使用的全局变量或函数要加范围限定符(建议使用模块名(缩写)作为范围限定符),比如GUI_等。
        (2)标识符的命名规则
             a:标识符名分为两部分:规范标识符前缀(后缀)+ 含义标识。非全局变量可以不使用范围限定符前缀。
               标识符名的组成如下:
        模块名缩写 -- 作用域前缀 数据类型前缀 【指针前缀】 含义标识 数组、结构后缀
             b:作用域前缀命名规则
                
               序号               标识符类型                  作用域前缀
                1                Global Variable                  g
                2                File Static Variable             n
                3                Function Static Variable         f
                4                Auto Variable                    a
                5                Global Function                  g
                6                Static Function                  n
             c:数据类型前缀命名规则
               略
             d:含义标识命名规则,变量命名使用名词性词组,函数命名使用动词性词组
               变量含义标识符构成:目标词+动词(过去分词)+【状语】+【目的地】
              函数含义标识符构成:动词(一般现在时)+目标词+【状语】+【目的地】
             e:程序中不得出现仅靠大小写区分的相似的标识符。
             f:一个函数名禁止被用于其他之处。
             g:所有宏定义、枚举常数、只读变量全用大写字母命名,用下划线分割单词。
               const int MAX_LENGTH = 100;//这不是常量,而是一个只读变量
             h:考虑到习惯性问题,局部变量中可采用通用的命名方式,但仅限于n、i、j等作为循环变量使用。
               一般来说习惯上用n,m,j,i,k等表示int类型的变量;c,ch等表示字符类型变量;a等表示数组;p等表示指针。
             i:结构体被定义时必须有明确的结构体名。另外,所有结构和联合的类型在转换单元的结尾应该是完整的。
             j:定义变量的同时千万别忘了初始化。定义变量时编译器并不一定清空了这块内存,它的值可能是无效的数据。
             k:不同类型数据之间的运算要注意精度扩展问题,一般低精度数据向高精度数据扩展。
             l:禁止使用八进制的常数(0除外,因为严格意义上来讲0也是八进制数)和八进制数的转义字符。
        (3)signed,unsigned             
             a:单纯的char类型应该只用于字符值的存储和使用‘有符号和无符号的“char”型变量只能用于数值的存储和使用。===》
              char有三种不同的类型:单纯char、signed char 及 unsigned char.
              signed char 和 unsigned char 类型是用来声明数值的;单纯char类型是真正的字符类型,是用来声明字符的。对于单纯char类型,唯一允许的操作是赋值和相同运算符(=              ,==,!=)。
             b:所有无符号型常量都应该带有字母U后缀
         (4)if.else组合
          @1.bool变量与“零值”进行比较
          写法:   if(bTestFlag)     if(!bTestFlag)
          大家都知道if语句是靠其后面括号里的表达式的值来进行分支跳转。表达式如果为真,则执行if语句后面紧跟的代码;否则不执行。那显然,本组的写法很好,既不会引起误会,也不会由于TRUE 或FALSE 的不同定义值而出错。记住:以后写代码就得这样写。
          @2.float变量与“零值”进行比较
          写法:   if((flestVal >= -EPSINON) && (flestVal <= EPSINON))//EPSINON 为定义好的精度
              a:使用浮点数应遵循已经定义好的浮点数标准。
                    在表示浮点数的各个字节中,究竟用多少为表示小数部分,多少位表示指数部分,标准C中无具体定义。
                    ANSI/IEEE标准的基本规定如下所述:
                        *两种基本浮点格式:单精度和双精度。
                        *两种扩展浮点格式:单精度扩展和双精度扩展。
                        *浮点运算的准确度要求:加,减,乘,除,平方根,余数,将浮点格式的数舍入为整数,在不同浮点格式之间转换,在浮点和整数格式之间转换以及比较。
                        *在十进制字符串和两种基本浮点格式之一的二进制浮点数之间进行转换的准确度,单一性和一致性要求。
                        *五种类型的IEEE浮点异常,以及用于向用户指示发生这些类型异常的条件。
                         五种类型的浮点异常是:无效运算,被零除,上溢,下溢和不精确。
                        *四种射入方向:
                             &向最接近的可表示的值;
                             &当有两个最接近的可表示的值时,首选“偶数”值;
                             &向负无穷大(向下);
                             &向正无穷大(向上)以及向0(截断)。 
          @3.指针变量与“零值”进行比较
          写法:    if(NULL == p)    if(NULL != p)
          @4.else 到底与哪个 if 配对
          c语言有这样的规定:else始终与同一括号内最近的未匹配的if语句结合。
                a:程序中的分界‘{’和‘}’对齐风格:
                      代码的缩进一般为4个字符,但不要使用Tab键,因为不同的编辑器Tab键定义的空格数量不一样,别的编辑器打开Tab键缩进的代码可能会一片混乱。
          @5.if语句后面的分号
      if(NULL != p);
           相当于
           if(NULL != p)
           {
                ;
      }
      建议在真正需要用空语句时写成这样:
            NULL;而不是单用一个分号。
          @6.使用if语句的其他注意事项
                 a:先处理正常情况,再处理异常情况。
                       因为,if语句总是需要做判断,而正常情况一般比异常情况发生的概率更大。如果把执行概率更大的代码放到后面,也就意味着if语句将进行多次无所谓的比较。另外,非常重要的一点是,把正常情况的处理放在if后面,而不要放在else后面。当然这也符合把正常情况的处理放在前面的要求。
                 b:确保if和else子句没有弄反。
                 c:赋值运算符不能使用在产生布尔值的表达式上。
                 d:所有的if-else if 结构应该由else 子句结束。
                       不管何时一条if语句后有一个或多个else if语句都要应用本规则;最后的else if必须跟有一条else 语句。而if语句之后就是else语句的简单情况不在本规则之内。
                       对最后的else语句的要求是保护性编程。else语句或者要执行适当的动作,或者要包含合适的注释以说明为何没有执行动作。这与switch语句中要求具有最后一个default子句是一致的。
         (5)switch,case组合
          @1.if,else一般表示两个分支或是嵌套比较少的分支,但如果分支很多的话,还是用switch,case组合吧,这样可以提高效率。
                 a:每个case语句的结尾绝对不要忘了加break,否则将导致多个分支重叠(除非有意使多个分支重叠)。
                 b:最后必须使用default分支。即使程序真的不需要default处理,也应保留default语句。
                 c:在switch case组合中,禁止使用return语句。
                 d:switch表达式不应是有效的布尔值。
          @2.case关键字后面的值的要求:
          case后面只能是整型或字符型的常量或常量表达式。
          @3.case语句的排列顺序
                 a:按字母或者数字顺序排列各条case语句。
                 b:把正常情况放在前面,而把异常情况放在后面。
                   如果有多个正常情况,把正常情况放在前面,并做好注释;把异常情况放在后面,同样要做好注释。
                 c:按执行频率排列case语句。
                   把最常执行的情况放在前面,而把嘴不常执行的情况放在后面。最常执行的代码可能也是调试的时候要单步执行最多的代码。如果放在后面的话,找起来可能会比较困难,而放在前面的话,可以很快找到。
          @4.使用case语句的其他注意事项
                 a:简化每种情况对应的操作。
                  case语句后面的代码越精炼,case语句的结果就会越清晰。如果某个case语句确实需要这么多的代码来执行某个操作,那可以把这些操作写成一个或几个子程序,然后在case语句后面调用这些子程序就可以了。一般来说,case语句后面的代码尽量不要超过20行。
                 b:不要为了使用case语句而刻意制造一个变量。
                   case语句应该用于处理简单,容易分类的数据。如果你的数据并不简单,那么会用if-else if的组合更好一些。如果为了使用case而刻意构造出来的是很容易把人搞糊涂的变量,那么就应该避免这种变量。
                 c:将default子句只用于检查真正的默认情况。
                   如果将最后一种情况用default来处理,这样将失case语句的标号所提供的自说明功能,而且也丧失了使用default子句处理错误情况的能力。所以,要把每一种情况都用case语句来完成,而把真正默认情况的处理交给default子句。
          (6)do,while,for关键字
           @1.break,与continue的区别
           break关键字表示终止本次循环;
           continue关键字表示终止本次(本轮)循环,进入下一轮循环。
           while(1)也有写成while(true),while(1==1),while((bool)1)等形式的,效果一样。
           @2.循环语句的注意点
                 a:在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环层的次数。
                 b:建议for语句的循环控制变量的取值采用“半开半闭区间”写法。(更直观)
                 c:不能在for循环体内修改循环变量,防止循环失控。
                 d:循环要尽可能短,要使代码清晰,一目了然。
                   一般来说,循环内的代码不要超过20行。要不然,就将这些代码改写成一个子函数,循环中只调用这个子函数即可。
                 e:把循环嵌套控制在三层以内。
                 f:for语句的控制表达式不能包含任何浮点类型的对象。
                   舍入误差和截取误差会通过循环的迭代过程传播,导致循环变量的显著误差,并且在进行检测时很可能给出不可预期的结果。
           (7)goto关键字
                 a:禁用goto语句。
                   首先,由于goto语句可以灵活跳转,如果不加限制,它的确会破坏结构化设计风格;
                   其次,goto语句经常带来错误或隐患,他可能跳过了变量的初始化,重要的计算等语句。
           (8)void关键字
            @1.void a
            void 真正发挥的作用在于:对函数返回的限定;对函数参数的限定。
            void * ,任何类型的指针都可以直接赋值给它,无需进行强制类型转换;
            但这并不意味着,void * 也可以无需进行强制类型转换地赋值给其他类型的指针。
            @2.void修饰函数返回值和参数
                  a:如果函数没有返回值,那么应将其声明为void类型。
                    在c语言中,凡不加返回值类型限定的函数,就会被编译器作为返回整型值处理。加上void类型声明后,可以发挥代码的“自注释”作用。所谓代码的“自注释”即代码能自己注释自己。
                  b:如果函数无参数,那么应声明其参数为void。
                    在c语言中,可以给无参数的函数传送任意类型的参数,但是在C++中,不能向无参数的函数传送任何参数。
                    所以,无论在C还是C++中,若函数不接受任何参数,则一定要指明参数为void。
            @3.void指针
                  a:千万小心地使用void指针类型。
                    按照ANSI标准,不能对void指针进行算法操作。
                    ANSI标准之所以这样认定,是因为它坚持:进行算法操作的指针必须是确定知道其指向数据类型大小的,也就是说必须知道内存目的地址的确切值。
                  b:如果函数的参数可以是任意类型指针,那么应声明其参数为void*。
            @4.void不能代表一个真实的变量。
                  a:void不能代表一个真实的变量。因为定义变量时必须分配内存空间,定义void类型变量编译器到底分配多大的内存,不知道。
            (8)return关键字
             return用来终止一个函数并返回其后面跟着的值。
                  a: re,因为该内存函数体结束时被自动销毁。
            (9)const关键字也许该被替换为readonly//execl表格中
            (10)最易变的关键字--volatile
                  volatile是易变的,不稳定的意思。
                  volatile关键字和const一样是一种类型修饰符。遇到这个关键字声明的变量,编译器对访问该变量的代码就不在进行优化,从而可以提供对特殊地址的稳定访问。
                  volatile int i= 10;
                  int j = i;
                  int k = i;
                  volatile关键字告诉编译器,i是随时可能发生变化的,每次使用它的时候必须从内存中取出i的值,因而编译器生成的汇编代码会重新从i的地址处读取数据放在k中。
            (11)extern
                  extern可以置于变量或函数前,以表明变量或函数的定义在别的文件中,下面代码用到的这些变量或函数是外来的,不会死本文件定义的,提示链接器遇到此变量和函数时在其他模块中解析/绑定此标识符。
           (12)struct 关键字
                  struct 是个神奇的关键字,它将一些相关联的数据打包成一个整体,方便使用。
              @1.空结构体多大
                 结构体所占的内存的大小是其成员所占内存之和。
                 编译器理所当然地认为,你构造一个结构体数据类型是用来打包一些数据成员的,而最小的数据成员需要1字节,编译器为每个结构体类型数据至少预留1字节的空间。所有,空结构体的大小就定为1字节。
              @2.柔性数组(flexible array)
                 结构中的最后一个元素允许是未知大小的数组,着就叫做柔性数组成员,但结构中的柔性数组成员前面必须至少有一个其他成员。柔性数组成员允许结构中包含一个大小可变的数组。sizeof返回的这种结构大小不包括柔性数组的内存。包含柔性数组成员的结果用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
                  typedef struct st_type
                  {
                      int i;
                      int a[];
                   }type_a;
                   
 type_a *p = (type_a *)malloc(sizeof(type_a) + 100*(sizeof(int));
             @3.struct与class的区别
                  struct的成员默认情况下的属性是public,而class成员的却是private.
             (13)union关键字
                 union维护足够的空间来放置多个数据成员中的“一种”,而不是为每一个数据成员配置空间。在union中所有的数据成员共用一个空间,同一时间只能储存其中的一个数据成员,所有的数据成员具有相同的起始地址。
                 一个union只配置一个足够大的空间来容纳最大长度的数据成员。
                在C++中,union的成员默认属性为public。union主要用来压缩空间。如果一些数据不可能在同一时间同时被用到,则可以使用union。
               @1.大小端模式对union类型数据的影响
                  大端模式:字数据的高字节存储在低地址中,而子数据的低字节则存放在高地址中。
                  小端模式:字数据的高字节存储在高地址中,而字数据的低字节则存放在低地址中。
                  union型数据所占的空间等于其最大的成员所占的空间。对union型成员的存取都从相对于该联合体基地址的偏移量为0处开始,也就是联合体的访问不论对哪个变量的存取都是从union的首地址位置开始。
               @2.如何用程序确认当前系统的存储模式
                    a:对于位域的使用和自定义的行为需要详细说明,且在使用前需要用代码check当前系统的模式(大端或小端模式)。使用位域时,需要特别注意对齐方式是LSB或是MSB。???
                    b:使用带符号的位域,至少需要两位来表示一个完整的位域。第一位是符号位,0表示正数,1表示负数;其余位数表示数值。
                      负数是按照补码的方式来表示的。
           (14)enum关键字(枚举)
               @1.枚举类型的使用方法
                  实际上枚举变量类型是对一个变量取值范围的限定,而花括号内是它的取值范围,即枚举变量的变量只能取值为花括号内的任何一个值,如果赋给该类型变量的值不在列表中,则会报错或者警告。
                  enum变量类型还可以给其中的常量符号赋值,如果不赋值则会从被赋初值的那个变量开始依次加1;如果都没有赋值,它们的值从0开始依次递增1.
               @2.枚举与#define宏的区别
                  A:#define宏常量是在预编译阶段进行简单替换;枚举常量则是在编译的时候确定其值。
                  B:一般在调试器里,可以调试枚举常量,但是不能调试宏常量。
                  C:枚举可以一次定义大量相关的常量,而#define宏一次只能定义一个。
             (15)typedef关键字
               @1. typedef的真正意思是给一个已经存在的数据类型(注意:是类型不是变量)取一个别名,而非定义一个新的数据类型。
                   在实际项目中,为了方便,可能很多数据类型(尤其是结构体之类的自定义数据类型)需要我们取一个适用于实际情况的别名。
                   a:用typedef重命名基本的数据类型,以替代原始的数据类型。
            
         typedef                  char                   char_t
         typedef  signed          char                   int8_t?
         typedef  signed          short                  int16_t
         typedef  signed          int                    int32_t
         typedef  signed          long                   int64_t
         typedef  unsigned        char                   uint8_t?
         typedef  unsigned        short                  uint16_t
         typedef  unsigned        int                    uint32_t

         typedef  unsigned        long                   uint64_t          

          typedef                  float                 float32_t

         typedef                  double                float64_t
         typedef  long            double               float128_t
            
               @2.typedef与#define的区别
            
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值