C语言-细节

C语言-细节

  • Fang XS.
  • 1452512966@qq.com
  • 如果有错误,希望被指出,学习技术的路难免会磕磕绊绊,不定期更新

摘要

  • 小技巧
  • 宏定义中的# ##
  • 副作用与序列点
  • 数字的前缀与后缀
  • 关于变量
  • 关键字const
  • 关键字static
  • 关键字volatile
  • 关键字extern
  • 结构体

小技巧

  • 在C中,任何数据类型都不占内存,只有数据实体占内存。
  • 整形常量可以使用匿名枚举enum {eTest =5};,这样比#define定义的整形更安全。
  • 浮点型常量可以使用const定义。

宏定义中的# ##

  • #的作用啊将括号中的参数转换成字符串。
  • #在宏定义中一般形式为:
    #define  ToString(x)   (#x)
    
  • 就可以这样使用:
    printf("%s\n",ToString(TestString));
    // ToString(TestString) 被替换成了 "TestString"。
    // 相当于:
    // printf("%s\n","TestString");
    

  • ##是连接符,将前后两个东西连接成一个整体。
  • 例如:
    #define func(NAME,NUM) void NAME##NUM(void)
    
    func(test,1)	// 相当于 void test1(void)
    {
        printf("this is a test function.\n");
    }
    //在main函数中就可以这样调用:
    test1();
    

副作用与序列点

  • 副作用
    • 副作用是指对数据对象或文件的修改。
    • 对于表达式来说, 主要作用是求表达式的值, 其他作用为副作用。
    • 例如,a=3;C会对表达式进行求值,表达式值为3,而a这个对象的值也被修改成3
  • 序列点
    • 序列点有: 完整表达式(full expression), 表示语句结束的分号, 逻辑运算符 && 和 ||, 逗号运算符。
    • 程序执行到序列点时, 所有副作用都在序列点之前发生。
    • 例如,a=3;,程序修改了a的值就是副作用,这个副作用在这个语句的序列点;之前发生。
  • C标准
    • C标准规定:在两个序列点之间,一个对象所保存的值最多只能被修改一次。
    • C标准规定:在两个序列点之间,副作用的执行顺序是不确定的。
    • C标准规定:两个序列点之间的执行顺序是任意的。当然这个任意是在不违背操作符优先级和结合特性的前提下的,这个规定的意义是为编译器的优化留下空间。
  • 总结
    • 这样看来,我们写C程序大多数情况就是在用C的副作用。
    • 尽量不要这样写a = i++ + ++j;这样的代码,碰到考试或者面试,先分析表达式的运算优先级,i++先取值后自增,++j先自增再取值。

数字的前缀与后缀

  • 在数据前后加前后缀通常是为了指明常量的数据类型,以便与变量的数据类型保持一致或保证数据运算的正确性.
  • 前缀(大小写都一样)
    • 0x表示该数值是十六进制表示的。
    • 0表示该数值是八进制表示的。
  • 后缀(大小写都一样)
    • U表示该常数用无符号整型方式存储,相当于unsigned int.
    • L表示该常数用长整型方式存储,相当于long.
    • F表示该常数用浮点方式存储,相当于float.

关于变量

  • C语言变量定义格式 存储类型 特征修饰 数据类型 变量名;
    • 存储类型:决定变量的存储位置。
      1. auto用来修饰局部变量,具有局部作用域,局部生命周期,存储在栈上,一般局部变量默认为auto类型。
      2. static修饰的:(下文关键字详述)
        • 局部变量具有局部作用域,全局生命周期,存储在全局区。
        • 全局变量具有模块作用域,全局生命周期,存储在全局区。
      3. extern修饰的全局变量具有全局作用域,全局生命周期,存储在全局区。
      4. register用来修饰局部变量,具有局部作用域,局部生命周期
        • register修饰变量不能被取地址。
        • 因为CPU寄存器有限,可能会存储在CPU寄存器中,CPU寄存器的速度比存在内存中快。
    • 特征修饰:决定变量的特征属性。
      1. const修饰的变量具有只读的属性。(下文关键字详述)
      2. volatile 修饰的变量,提醒编译器随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。(下文关键字详述)
    • 数据类型:决定变量的数据类型。
      • C中的基本数据类型包括整型和浮点型。不同的基本数据类型修饰的变量,区别是所占存储空间不一样,所表示的数值范围也不一样。
    • 变量名:决定变量的引用标识。
      • 遵循标识符命名规则:
        • 不使用关键字,系统预定义标识符等。
        • 由数字,字母,下划线组成的,且数字不可以作为开头。
        • 严格区分大小写。
        • 不同编译器,不同标准,标识符长度限制不一样,最好小于32个字符。

关键字const

  • 关于const修饰变量
    • 在C中,const所修饰的变量,具有只读属性。
    • 在C中,const所修饰的变量,本身还是变量,只是被限定为只读,不可修改。
    • 在C中,const所修饰的变量,被限定为只读属性,通过非常规操作还是可以改,这里不讨论。
  • 关于const修饰指针
    1. const int *p修饰指针p所指向的值不可改,常量指针。
    2. int const *p修饰指针p所指向的值不可改,常量指针。
    3. int * const p修饰指针p不可改,指针常量。
    4. const int * const p修饰指针和指针p所指向的值不可改,指向常量的指针常量。
    • 总结
      • const修饰指针,分3种情况,修饰指针指向的值,修饰指针,修饰指针和指向的值。
      • 修饰指针不可改,const放在*的右边。
      • 修饰指针指向的值不可改,const放在*的左边。
      • 修饰指针和指向的值都不可改,const*的左边和右边。
      • 在函数中,const一般用来修饰形参,来确保传进的值或指针,不被本函数修改。

关键字static

  • 在C中, static使用恰当能够大大提高程序的模块化特性,有利于扩展和维护。
  • 在C中, static用来修饰变量 称静态变量
    • 函数内局部变量
      • 函数内局部变量,只具有局部作用域,局部生命周期,在栈区分配内存空间。
      • static修饰的局部变量称静态局部变量。
        • 具有局部作用域,全局生命周期。
        • 静态局部变量,只被初始化一次,在全局数据区分配内存空间。
    • 函数外全局变量
      • 函数外全局变量,具有全局作用域,全局生命周期,在全局数据区分配内存空间。
      • static修饰的全局变量称静态全局变量
        • 具有文件作用域,全局生命周期,只在模块内访问,在全局数据区分配内存空间。
  • 在C中, static用来修饰函数 称静态函数
    • 静态函数只能在声明它的文件中可见,其他文件不能引用该函数。
    • 不同的文件可以使用相同名字的静态函数,互不影响。
  • 不被static修饰的函数,隐含被声明为extern,其他文件可以访问。

关键字volatile

  • 翻译过来是 adj.易变的,动荡不定的,反复无常的;
  • volatile声明的变量,提醒编译器随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。
  • 现在的编译器趋向于智能化,经过时间的沉淀,bug越来越少,越来越智能,甚至有的变量,编译器可能优化读取和存储,来提升程序的速度和性能。
  • 在嵌入式中,有些指针存储的是寄存器的地址,而寄存器的值可以不仅仅被程序改变,也可以被外设,或者引脚电平变化而随之改变,这样一来,如果编译器对其进行优化,暂时使用寄存器中的值,那么编译器优化保存的值,跟实际的值是不一样的,会出现bug。

关键字extern

  • 在C中,extern修饰的全局变量,具有全局作用域,全局生命周期,存储在全局区,可以被跨文件使用。
  • 在C中,extern指示编译器去别处查询其定义。
  • 在C中,用 extern 关键字声明定义在其他文件中的函数。这样做是为了表明当前文件中使用的函数被定义在别处。除非使用static关键字,否则一般函数声明都默认为extern

结构体

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值