主要内容包括预处理命令、宏定义、条件编译、标准头文件写法以及C语言中指针的概念与使用。

一、C语言的编译过程

C语言的完整编译过程分为四个阶段:

  1. 预处理:处理#include#define、条件编译等指令,进行文本替换。

  2. 编译:    将预处理后的代码编译成汇编代码。

  3. 汇编:    将汇编代码转化为目标文件(.o 或 .obj)。

  4. 链接:    将多个目标文件链接为可执行程序。

其中,预处理的本质就是文本替换,这对后续编译影响很大。


二、宏定义

1. 不带参数的宏定义

语法:#define 标识符 替换内容

例如:

#define PI 3.14

使用时:

float area = PI * r * r;

注意:宏是纯文本替换,不参与计算,末尾不能加分号,否则会一并被替换,引发语法错

误。

eg: 加上括号保证优先级  


2. 带参数的宏定义

语法:#define 宏名(形参表) 宏内容

例如:

#define MAX(a, b) ((a) > (b) ? (a) : (b))

使用示例:

int x = 5, y = 10; int max = MAX(x, y);

括号加得越多越安全,避免运算符优先级造成错误。宏展开是直接替换文本,不需要保护现场,所以执行效率高但代码体积变大。

宏与函数的本质区别:
  • 宏是直接进行文本替换,不进行类型检查,也不参与函数调用机制。它在预处理阶段就被展开,不会产生函数调用开销,也不会保护现场和恢复现场。

  • 函数则是在编译阶段编译生成机器代码,具有参数检查、类型检查等机制,并需要执行时进行调用、压栈、返回等操作。

只是做文本替换,不计算,输出结果为15

//3>4+5加号优先级高,所以3>9,输出结果为0

例题:给定三角形三边求三角形面积(用宏)


三、文件包含

语法:

#include <stdio.h> // 系统路径查找

#include "func.h" // 当前目录查找

实质也是文本替换,不参与编译。头文件用于声明函数或变量,不能包含函数定义。


四、条件编译

用法1:

#if 0 // 这段代码会被替换为空

#endif

用法2:

#ifdef DEBUG // 如果宏 DEBUG 被定义,编译这段

#else // 否则编译这一段

#endif

用法3:

#ifndef FUNC_H

#define FUNC_H // 头文件内容

......

#endif

常用于防止头文件重复包含。


五、指针基础

1. 指针概念

指针是一种用来存储地址的变量。地址即数据在内存中的编号。

int i = 10;

int *p = &i; // p 是指向 int 型的指针,保存变量 i 的地址(此处*声明p是个存地址的变量)

*p = 100; // 通过指针 p 修改 i 的值(此处*是指针运算符,说明指向 i 的内容)

2. 指针语法

类型 *指针名;

例如:

int *p; // 指向 int 类型的指针

char *cp; // 指向 char 类型的指针

*在定义时表示“指针类型”;在使用时表示“间接访问”。


3. 间接访问的三大步骤:

  1. 根据指针变量中的值去内存中定位;

  2. 从定位处开始向后偏移sizeof(基类型)个字节;

  3. 将偏移后的那部分内存空间当作一个基类型变量来看。


4. 指针作为函数参数

值传递:

void change(int a)

{

    a = 100;

}

int main()

{

    int x = 10;

    change(x); // x 仍为 10

}

地址传递(指针传递):

void change(int *p)

{

    *p = 100;

}

int main()

{

    int x = 10;

    change(&x); // x 被修改为 100

}

要修改谁,就传它的地址。指针参数本质上就是“地址传递”,可以在被调函数中修改主调函数中的数据。所有指针在 64 位系统下占 8 个字节,在 32 位系统下占 4 个字节,不随基类型变化而改变。

指针百分之八十的用途:在函数内部可实现在被调函数中修改主调函数

eg:

       int  *p;

      *p = 100;

      *p为野指针,编译不报错,运行程序崩溃(断错误)

       注:被调函数中,一定要有*p运算,间接访问操作;

              指针变量(野指针)与指针变量t指向的变量应都是确定的。


六、标准头文件防止重复包含

写头文件时,通常加如下模板:

#ifndef FUNC_H

#define FUNC_H

void myFunction();

#endif

这可以避免多个文件重复包含头文件,导致重复定义错误。

七、练习

用指针方式求3个数的和

求3个数最大,最小值

交换两数(注意不要将t写为*t,因为*a,*b已经指向i和j了,已经是整型数字了)

输出类型选择

前3个表达式输出的都是i的地址(*与&可抵消);

后2个表达式第一个输出i本身,第二个编译报错。

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐