嵌入式开发学习(第二阶段 C语言笔记)

发布于:2025-06-05 ⋅ 阅读:(18) ⋅ 点赞:(0)

预处理

C语言的编译步骤

  1. 预处理
  2. 编译
  3. 汇编
  4. 链接

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

什么是预处理

预处理就是在源文件(.c文件)编译之前,所进行的一部分备份操作,这部分是由预处理器(预处理程序)自动完成。当源文件在编译时,编译器会自动调用预处理程序来完成预处理执行的操作,预处理执行解析完成才能进入下一步的编译过程。

查看预处理的结果:

gcc 源文件 -E -o 程序名

预处理功能

宏定义
不带参数的定义
  • 语法:

    #define 宏名称 宏值(替换文本)
    
  • **预处理机制:**此时的预处理只是数据替换,不做类型检查

  • **注意:**宏定义不会占用内存空间,因为编译前已经将宏名称替换成宏值

  • **宏展开:**在预处理段将宏名称替换成宏名称替换成宏值的过程称之为“宏展开”。

  • 案例:

    /*************************************************************************
      > File Name:    demo01.c
      > Author:       小刘
      > Description:  
      > Created Time: 2025年05月29日 星期四 09时22分59秒
     ************************************************************************/
    
    #include <stdio.h>
    
    #define PI 3.1415926
    
    int main(int argc,char *argv[])
    {
        float l,s,r,v;
        printf("请输入圆的半径:");
        scanf("%f",&r);
    
        l = 2 * PI * r;
        s = r * r * PI;
        
        printf("l=%0.4f\ns=%0.4f\n",l,s);
    
        return 0;
    }
    

在这里插入图片描述
在这里插入图片描述

带参数的定义
  • 语法:

    #definr 宏名(参数列表) 替换表达式
    
  • 面试题:

    #define multi(a,b) (a) * (b)
    #define multi(a,b) a * b
    

    实现

/*************************************************************************
  > File Name:    demo02.c
  > Author:       刘孟丹
  > Description:  
  > Created Time: 2025年05月29日 星期四 10时24分27秒
 ************************************************************************/

#include <stdio.h>

// 带参数的宏定义,宏名一般小写
#define mult_1(a,b) (a)*(b)
#define mult_2(a,b)  a * b

int main(int argc,char *argv[])
{
    int result1 = mult_1(7+2,3);
    printf("%d\n",result1);

    int result2 = mult_2(7+2,3);
    printf("%d\n",result2);
    return 0;
}
宏定义的作用域
  • #define命令出现程序中函数的外面,宏名的有效范围为定义命令之后到本源文件结束。

  • 可以用#undef命名终止宏定义的作用域。

  • 案例:

    /*************************************************************************
      > File Name:    demo03.c
      > Author:       刘孟丹
      > Description:  
      > Created Time: 2025年05月29日 星期四 10时32分45秒
     ************************************************************************/
    
    #include <stdio.h>
    
    #define PI 3.14 //PI的作用域 10行~19行
    #define DAY 29
    
    void func1()
    {
        float r  = 4 ;
        float s = PI * r * r;  // 预处理后 
        int day = DAY;         // 
    }
    
    #undef PI //终止了PI的范围
    
    #define PI 3.1415926
    
    void func2()
    {
        float r  = 4 ;
        float s = PI * r * r;   
        int day = DAY;
    }
    
    
    
    int main(int argc,char *argv[])
    {
    
        return 0;
    }
    

    宏定义中引用已定义的宏明

  • 案例

    /*************************************************************************
      > File Name:    demo04.c
      > Author:       小刘
      > Description:  
      > Created Time: 2025年05月29日 星期四 10时39分52秒
     ************************************************************************/
    
    #include <stdio.h>
    
    #define R 3.0 //半径
    #define PI 3.14
    #define L 2*PI*R // 周长 在宏定义的时候,引入已定义的宏名
    #define S PI*R*R  //面积
    
    #define P_WIDTH = 800
    #define P_HeIGTH = 480
    #define SIZE = p_HEIGHT * P_WIDTH 
    
    int main(int argc,char *argv[])
    {
    
        printf("L = %f\n s=%f\n",L,S)
        return 0;
    }
    
    

    预处理结果:

在这里插入图片描述

条件编译

**定义:**根据设定的条件选择待编译的语句代码。

预处理机制:将满足条件的语句进行保留将不满足的条件语句进行删除,交个下一步编译,

语法:

  • 语法1

    根据是否找到标记,来决定是否参与编译(标记存在为真,不存在为假

#ifdef 标记
... 语句代码1
#else 
... 语句代码2
#endif
  • 语法2

    根据是否找到标记,来决定是否参与编译(标记不存在为真,存在为假

    #ifndef 标记
    ... 语句代码1
    #else 
    ... 语句代码2
    #endif
    
  • 语法3

    根据表达式的结果,来决定是否参与编译(表达式成立为真,不成立为假

    ------ 单分支
    #if 表达式
    ... 语句代码
    #endif
    
    
    -----双分支结构----
    #ifdef 标记
    ... 语句代码1
    #else 
    ... 语句代码2
    #endif
    ----- 多分支 -----
    #if 表达式1
    ... 语句代码1
    #elif 表达式n
    ... 语句代码n
    #else
    ... 语句代码n+1
    #endif
    

案例:

/*************************************************************************
  > File Name:    demo05.c
  > Author:       刘孟丹
  > Description:  
  > Created Time: 2025年05月29日 星期四 11时30分59秒
 ************************************************************************/

#include <stdio.h>

// 定义一个条件编译的标记
#define LETTER 0 // 默认是大小



int main(int argc,char *argv[])
{
    // 测试用字母字符串
    char str[20] = "C language";

    char c;
    int i = 0;
    while((c = str[i]) != '\0')
    {
#if LENTTER
        if(c >= 'a' && c <= 'z')
        {
            c -= 32;
        }
#else
        if(c >= 'A' && c <= 'Z')
        {
            c += 32;
        }
#endif
        printf("%c",c);
        i++;

    }
    printf("\n");
    return 0;
}
概念

所谓“文件包含”处理是指一个源文件可以将另一个源文件的全部内容包含进来。这适合于多文件开发。通常,一个常规的C语言程序会包含多个源文件( *.c ),当某些公共资源需要在各个源文件中使用时,为了避免多次编写相同的代码,我们一般会进行代码的抽取( *.h ),然后在各个源文件中直接包含即可。

在这里插入图片描述

注意:*.h中的函数声明必须在*.c中有对应的函数定义,否则没有意义。(函数一旦声
明,就一定要定义)

头文件(.h)的内容

头文件中所存放的内容,就是各个源文件彼此可见的公共资源包括:

  • 全局变量声明
  • 普通函数的声明
  • 静态函数的定义
  • 宏定义
  • 结构体、共用体的定义
  • 枚举常量列表
  • 其他头文件包含

示例代码

myhead.h

extern int global;
extern void fun1();
static void fun2();
{
    ....
};

#define max(a,b) ((a) > (b) ? (a) : (b)) // 宏定义

struct node // 结构体定义
{
..
};

union attr // 共用体定义
{
..
};

enum SEX // 枚举常量列表定义
{
..
};

#include <stdio.h> // 引入系统头文件
#include "myhead2.h" // 引入自定义头文件

特别说明

  1. 全局变量、普通函数的定义一般出现在某个源文件(*.c)中其他源文件都需要进行声明。因此一般放在文件中更方便。
  2. 静态函数、宏定义、结构体、共用体、枚举的定义都只能在其他所在文件可见,因此如果多个源文件都需要的话,放到头文件中定义时最方便的选择。

预处理机制:将文件中的内容替换文件包含指令

包含方式
  1. #include <XXXXX.h>:系统会到标准库文件目录(Linux下/usr/include)查找包含文件建议对于系统库访问采用这种写法。
  2. #include "xxxx.h" :在当前工程路径下(Linux下 ./ )查找包含的文件,如果未找到,就去标准库文件目录下查找。建议对于自定义库采用这种写法。
案例
  • myhead.h

    /*************************************************************************
      > File Name:    myhead.h
      > Author:       小刘
      > Description:  
      > Created Time: 2025年06月01日 星期日 19时24分29秒
     ************************************************************************/
    
    #ifndef _MYHEAD_H
    #define _MYHEAD_H
    
    /**
     * 数组的累加和运算
     * @param int *int数组
     * @param int 数组大小
     */
    extern int sum(const int*,int);
    
    #endif //_MYHEAD_H
    
    
  • myhead.c

    /*************************************************************************
      > File Name:    myhead.c
      > Author:       小刘
      > Description:  
      > Created Time: 2025年06月01日 星期日 19时34分24秒
     ************************************************************************/
    
    #include <stdio.h>
    
    int sum(const int *arr,int len)
    {
    
        const int *p = arr;
        int sum = 0;
        for(;p < arr + len; p++)
        {
            sum += *p;
        }
        return sum;
    }
    
  • app.c

    /*************************************************************************
      > File Name:    app.c
      > Author:       小刘
      > Description:  
      > Created Time: 2025年06月01日 星期日 19时41分43秒
     ************************************************************************/
    
    #include <stdio.h>
    #include "myhead.h"
    
    int main(int argc,char *argv[])
    {
        int arr[] = {11,12,13,14,15};
    
        int result = sum(arr,sizeof(arr)/ sizeof(arr[0]));
    
        printf("数组累加和的结果是%d\n",result);
    
        return 0;
    }
    
  • 多条件编译命令

    gcc app.c myhead.c -o app
    
避免头文件重复包含的方法

其实就是头文件去重复。

由于头文件包含指令#include的本质是复制粘贴,并且一个头文件中可以嵌套包含其他头文件,因此很容易出现头文件被重复包含的情况。此时就需要我们进行去重,去重需要用到预处理提供的去重相关指令。

语法:

#ifndef XXXX_H // 一般为 头文件名大写+下换线+H
#define XXXX_H
..
#endif

案例:

/*************************************************************************
  > File Name:    myhead.h
  > Author:       小刘
  > Description:  
  > Created Time: 2025年06月01日 星期日 19时24分29秒
 ************************************************************************/

#ifndef _MYHEAD_H
#define _MYHEAD_H

/**
 * 数组的累加和运算
 * @param int *int数组
 * @param int 数组大小
 */
extern int sum(const int*,int);

#endif //_MYHEAD_H


网站公告

今日签到

点亮在社区的每一天
去签到