目录

嵌入式八股C语言-变量与运算符篇

嵌入式八股C语言—变量与运算符篇

变量

  1. 全局变量与局部变量重名

    可以的 此时全局变量就失效了

  2. 全局变量能否放在头文件中

    没有问题,但不太推荐

  • 2.1做法一:

    如果是不小心重名了,但是实际上这俩变量根本没任何关系,那就用static修饰,这样变量的作用域就会限制在本文件内,此时每个.c文件的变量都独立的 没关系

  • 2.2做法二:

    只有一个头文件初始化了这个全局变量,别的头文件没初始化就行;

    做法二涉及到了 符号决议 + 试探性定义 (链接的时候的事情,后面细讲)

    我们在linux中运行如下代码

        // a.h
        // int global_K = 10;
        // b.c
        #include <stdio.h>
        #include "a.h"
        int global_k;
        int main()
        {
            printf("%d\r\n",global_k);
        }
        // 打印的值是20

当然这个也看具体编译和链接的实现,作者在windows下这么干就直接报错了…

  • 2.3做法三:

    在需要用到全局变量的头文件中extern 声明

    最好还是头文件声明 + 源文件定义啦

  1. 变量的 存储类型 作用域 生命周期 链接属性
  • 3.1存储类型

    变量的存储类型决定于我们前面的存储类关键字 不同的存储类关键字决定了变量定义在不同位置(这也是为啥这几个关键字不能一起用)

    auto: 放在栈中 局部变量 随着函数调用结束就销毁了

    static: 放在静态存储区: BSS段(未初始化的静态变量) / 放在数据段(初始化的静态变量)

    register: 建议编译器放在寄存器中–此时不能对变量做求址运算

    extern: 声明了变量的链接属性

  • 3.2作用域

    变量的有效范围

    • 局部变量(不管static修饰不修饰)

      作用域就限定在函数(或者说花括号里)死死的

      int main()

      { // 直接就报错了

      {

      int i;

      }

      printf(“%d\r\n”,global_k,i);

      }

    • 全局变量

      默认作用域是整个文件(a.c 定义 b.c只要extern了同名变量就能用)

      也可以static修饰限制到a.c本身

  • 3.3生命周期

    变量的一生无非是: 创建->存在->销毁

    全局变量生命周期:和程序一样

    栈上的局部变量生命周期:随着函数调用结束结束了

    堆上变量的生命周期:由程序员管理

  • 3.4链接属性

    外部链接属性 / 内部链接属性 / 无链接属性

    外部链接属性: 全局变量 / 函数

    内部链接属性: static 修饰的 变量/函数 只能在本文件内部

    无链接属性: 局部变量不能被链接

    所以存储类关键字实现上决定了变量的存储类型 / 作用域 / 生命周期

运算符

  1. 优先级

    不用死记硬背 但是得知道最基本的

    • 比如最高的是 () [] -> .
    • & 和 * 是第二高的,不是第一高的!
  2. 分析组合起来的运算符

    https://i-blog.csdnimg.cn/direct/b0a0a0db5adb43768da2b5b36438d301.png

    int (*p)(int ,int );

    // 这是一个指针 名字叫p

    // 往右看(是个括号) 所以这个指针指向一个函数

    // 函数的返回值是int

    // 传入的参数是int 类型

  3. “=“运算符的返回值

    比如 while(a = b); // 不仅把值赋给了a 还会有一个返回值

    返回值是等号左边的变量的值

  4. " ++运算符”

    a++ 等价于 a = a + 1; //需要又一个temp存储临时结果

    ++a 是直接对a操作 不用临时变量 效果更好

    不过我能想到的 一般编译器也就想到做好优化了

  5. 强制类型转换

  • 5.1指针的强制转换

    这里后面指针在细细分析 毕竟指针的 +1 太有说法了

  • 5.2隐式类型转换–感觉和编译器有关系

    规则:从低精度向高精度、从有符号数向无符号数方向转换

    // 在算数运算中,所有比int小的都转换int进行计算 如果转int不够就转unsigned int计算

        void compare_data1(void){
            char a = -2;
            unsigned char b = 3;
            if( a < b)  // 打印的是这个 因为是按照int去做操作的(看汇编代码)
            {
                printf("a < b\n");
            }
            else{
                printf("a > b\n");
            }
            return;
        }  
        void compare_data2(void){
            int a = -2;
            unsigned int b = 3;
            if( a < b)
            {
                printf("a < b\n");
            }
            else{  // 实际打印是这个 因为都转为了无符号数
                printf("a > b\n");
            }
            return;
        }  

借着博客这里的答案来说:https://www.cnblogs.com/MinPage/p/14117237.html

https://i-blog.csdnimg.cn/direct/fc811f16fc3944e6ace7de8616b1925c.png

  1. 短路求值

    对于 || 运算符 从左向右运算 只要有一个为真 后面的就不算了

    对于 && 运算符 从左向右运算 只要有一个为假 后面的就不算了

  2. 左值与右值

  • 什么是左值、右值、对象、副作用、未定义行为

    • 左值:等于号左边的 一般来说值可以改变 就把左值当做 一块内存的别名 就行
    • 右值:表达式 具体的值往往运行期间才可以确定
    • 未定义行为: 数据访问越界 / 重复释放内存 / 直接操作未初始化的局部变量
  • 什么是结合性、左结合、右结合?

    结合性决定了当一个表达式中出现多个具有相同优先级的运算符时,这些运算符是如何组合的

    左结合意味着相同优先级的运算符会从左向右计算。

    右结合意味着相同优先级的运算符会从右向左计算。