嵌入式学习(C语言基础)
Apr 28. 2026

AI文摘
此内容由AI根据文章内容自动生成.
加载中。

Linux C语言程序设计

  1. 基础:数据类型,数据表现形式,运算符,表达式,语句, 三大设计结构
  2. 核心:数组,函数,指针
  3. 进阶:构造类型,预处理,库文件,标准文件流,位运算
  4. 高级:数据结构,算法,工程管理,工程调试,版本控制

C语言基础

  1. 编译过程:预处理、编译、汇编、链接
  2. printf 格式化列表:要求用一组 " " 括起来 格式化列表中可出现的内容:
  • 普通字符:格式化列表中的普通字符是原样输出的,
  • 转义字符:(\加上特定的字符) \n \t \0 \r
  • 格式化符:(%加上特定的字符) %c %d %e %s

C语言编码风格

  • 常用缩进书写格式
  • 有足够的注释
  • 有合适的空行
  • {}对齐
  • 函数体内采用分层缩进和模块化的书写方式
  • 不把多条语句写在程序的同一行上
  • 命名:变量或函数命名要尽可能包含更多含义,但不能太长,可采用_和缩写来命名

c语言数据类型

  1. 基本数据类型 数值类型:int,float,double 字符类型:char
  2. 构造数据类型 数组、结构体(struct)、联合体(union)、枚举(enum)
  3. 指针类型
  4. 空值类型:void
  5. 定义类型:typedef

进制转换

进制名称英文缩写数字符号集合进位规则常见前缀/后缀
十进制DEC0, 1, 2, 3, 4, 5, 6, 7, 8, 9逢十进一无 / D
二进制BIN0, 1逢二进一0b / B
八进制OCT0, 1, 2, 3, 4, 5, 6, 7逢八进一0 / O
十六进制HEX0-9, A(10), B(11), C(12), D(13), E(14), F(15)逢十六进一0x / H
  • 16转8: 先转换为二进制,从后往前看,每4位一组,每组转换成8进制,然后拼接起来。
  • 8进制转16: 先转换为二进制,每3位一组,每组转换成16进制,然后拼接起来。

数据表现形式

常量

  1. 整型常量
  2. 浮点型常量
  3. 字符型常量
  4. 符号常量

变量

不同类型数据在内存中的储存方式

整型数据
  • 在内存中是以补码方式存储的
  1. 原码: 将最高位作为符号位(0 表示正,1表示负),其他位代表了数据绝对值
  2. 反码: 如果是正数,反码就是原码,如果是负数,符号位不变,其余为按位取反
  3. 补码: 如果是正数,补码就是原码,如果是负数, 反码 + 1
  • 格式控制符

int 整型:%d short 整型:%hd, h代表half,即一半的存储字节 long 整型:%ld long long 整型:%lld 显示不同进制的前缀: %#o、 %#x

浮点型数据
  • (在内存中以二进制小数表示)以指数方式存储,数据分为指数与小数部分 符号位(1) + 指数位(8 /11) + 尾数(23 / 52)
  1. 浮点型数据先分别将整数部分与小数部分转换为二进制数据。
  2. 将转换后的数据以科学计数法的方式表示
  3. 根据数据的正负,确认最高位(符号位),然后将指数 + 指数偏移量(127 / 1023) 转换为8位数据 / 11位数据,将科学计数法表示的尾数部分(.以后)放置在最后的 23/52位

注意: 浮点型数据在内存中存储的是一个近似值,因为有些浮点型数据无法用有限数位来表示。

  • 面试题: 浮点型数据和 0 怎么比较?

定义一个极小的正数作为误差阈值(通常称为 Epsilon),只要浮点数的绝对值小于这个阈值,我们就认为它“等于” 0。

  • 字符型数据:

在内存中并不是存储字符本身,而是存储字符的ASCII码值

不同数据类型混合运算

类型转换方式:

  1. 隐式类型转换: 编译系统自动转化: 转换规则: 低优先级类型 —> 高优先级转换
  2. 强制类型转化: 程序员自行完成转换。 转换语法:(目标类型) 待转换数据/表达式;

printf 格式说明符

整型格式

格式说明符功能描述输出示例适用场景 / 备注
%d / %i有符号十进制整数123-456最常用的 int 类型输出;%i 在输入时可自动识别八/十六进制
%u无符号十进制整数45665535适用于 unsigned int,不输出负号
%o无符号八进制整数710177777默认不带前导0;加 # 修饰符(%#o)可自动补前导0
%x / %X无符号十六进制整数2af2AF字母分别为小写/大写;加 # 修饰符(%#x)可自动补前导 0x
%hhd / %hhu有符号/无符号 char65255char 类型专用,避免类型提升导致的输出异常
%hd / %hu有符号/无符号 short3276765535short 类型专用
%ld / %lu有符号/无符号 long123456789long 类型专用
%lld / %llu有符号/无符号 long long9223... (超大数)long long 类型专用,支持64位及以上超大范围整数

浮点型格式

格式说明符功能描述输出示例适用场景 / 备注
%f / %F十进制小数形式3.141593默认保留 6 位小数,自动四舍五入;%F 会大写输出 INF/NAN
%lf双精度浮点数3.1415926535double 类型专用(C99及以上标准),精度高于 %f
%e / %E科学计数法1.23e+02指数部分用小写 e 或大写 E,适用于超大/超小数值
%g / %G自动选择最短格式123.456自动在 %f%e 之间选择较短的表示,并去掉末尾无意义的 0
%a / %A十六进制浮点数0x1.92p+1C99 新增,用十六进制精确表示浮点数,避免十进制转换的精度损失
%Lf长双精度浮点数3.14159265...long double 类型专用,支持最高精度的浮点数输出

字符与字符串格式

格式说明符功能描述输出示例适用场景 / 备注
%c单个字符A\n输出 char 类型的单个字符,支持转义字符
%C宽字符适用于 wchar_t 类型,输出多字节宽字符
%s字符串Hello World输出以 \0 结尾的 char* 字符串,遇 \0 自动停止
%S宽字符串你好世界适用于 wchar_t* 类型,输出多字节宽字符串

特殊用途格式

格式说明符功能描述输出示例适用场景 / 备注
%p指针地址0x7ffe...输出 void* 类型的内存地址,标准十六进制形式
%n已输出字符计数(无直接输出)将当前已输出的字符总数写入对应的 int* 参数中,不产生任何显示内容
%%输出百分号%转义格式,用于在输出中打印 % 符号,避免被识别为格式说明符
%m输出系统错误信息No such file...GNU 编译器扩展,自动输出当前 errno 对应的系统错误描述

宽度与精度

  • %md:指定最小宽度为 m,不足用空格填充。
  • %.nf:浮点数保留 n 位小数。
  • %.ns:字符串最多输出前 n 个字符。

C 语言 I/O 缓冲区的“进与出”

问题场景涉及函数根本原因最佳解决方案
printf 后接死循环无输出printf (输出)输出缓冲区未刷新。
内容卡在内存里,没遇到换行或程序结束,导致没来得及显示。
在字符串末尾加上换行符 \n
(或者手动调用 fflush(stdout))
连续 scanf 第二个被跳过scanf (输入)输入缓冲区有残留。
前一次输入留下的换行符 \n 被后面的 %c 当作有效字符读走了。
%c 前加一个空格 " %c"
(或者用 getchar() 提前吃掉换行符)

查漏补缺

表达式优先级问题

优先级梯队包含运算符结合性说明
第1梯队 (最高)() [] . ->左→右括号、数组下标、成员访问
第2梯队! ~ ++ -- * & sizeof右→左单目运算符(逻辑非、指针、自增等)
第3梯队* / %左→右算术运算(乘除模)
第4梯队+ -左→右算术运算(加减)
第5梯队<< >>左→右移位运算
第6梯队< <= > >=左→右关系运算(比较大小)
第7梯队== !=左→右关系运算(比较相等)
第8梯队&左→右位运算(按位与)
第9梯队^左→右位运算(按位异或)
第10梯队|左→右位运算(按位或)
第11梯队&&左→右逻辑与
第12梯队||左→右逻辑或
第13梯队? :右→左条件运算符(三目)
第14梯队= += -=右→左赋值运算
第15梯队 (最低),左→右逗号运算符

整型运算核心

  1. 数据的底层存储法则(截断与溢出) 在计算机底层,数据最终都是以二进制比特序列的形式存在的。 截断机制:当把一个较大范围的数据类型(如 32 位整数)赋值给较小范围的类型(如 8 位字符)时,编译器会直接截取低位二进制存入,高位部分被丢弃。 溢出与重解释:如果截断后的二进制序列超出了目标类型的表达范围,计算机会按照目标类型的编码规则(有符号数通常采用补码)重新解释这段二进制,从而得到一个“面目全非”的数值。

  2. 运算与传参的预处理法则(整型提升) 为了保证 CPU 的运算效率,C 语言规定在表达式运算或作为可变参数(如 printf 的参数)传递时,所有小于 int 长度的整型(如 char、short)都必须先转换为 int(或 unsigned int)。这个转换过程称为“整型提升”,其核心规则如下: 有符号数的符号扩展:如果原类型是有符号的且值为负数(最高位是 1),提升时高位全部补 1;如果值为正数,高位全部补 0。这保证了提升前后的数值大小不变。 无符号数的零扩展:如果原类型是无符号的,无论数值是多少,提升时高位一律补 0。

  3. 格式化输出的解释法则(格式符决定视角) printf 等输出函数本身并不知道传入变量的真实类型,它完全依赖程序员提供的“格式控制符”来解读内存中的二进制数据。 有符号解读(如 %d):函数会将传入二进制序列的最高位视为符号位。如果是 1,则将其视为负数(补码)进行解析。 无符号解读(如 %u):函数会忽略符号位的概念,将传入的所有二进制位全部视为数值位,直接计算其代表的正整数大小。

  4. 混合运算的类型对齐法则(算术转换) 当不同长度的整数参与同一个数学运算时,编译器会按照“向长度更长、精度更高的类型对齐”的原则,自动将短类型转换为长类型,再进行计算。

  • 有符号与无符号的碰撞:当有符号整数与无符号整数进行运算时,如果它们的长度相同(例如都是 32 位),有符号数会被强制转换为无符号数参与运算。这意味着原本的负数会被当作一个极大的正数来处理,这往往是导致逻辑判断出现严重偏差的隐形陷阱。
#include <stdio.h>

int main() {
    // 初始化变量
    signed char a = -1;
    unsigned char b = 255;
    short c = -1;

    // 运算与输出
    printf("1. %d\n", a + b); // 254
    printf("2. %u\n", (char)b); // 2^32 - 1
    printf("3. %d\n", (unsigned short)c); // 65535

// 0000 0000 0000 0001
// 1111 1111 1111 1110
// 1111 1111 1111 1111 2^16-1 = 65535
    return 0;
}
  • 存储看补码,运算看提升,输出看格式。

数组

一维数组常见的陷阱

  1. 索引越界
  • 牢记数组下标从 0 开始,到 长度-1 结束。
  • 循环条件严格使用 i < 数组长度。
  1. 数组传参时的“长度消失”
  • 数组传参时,数组名会自动转换成指针,指针的 sizeof 为指针的大小,而不是数组的长度。
  • 在传递的时候需要额外增加一个长度的变量
  1. 返回局部数组的地址
  • 函数返回局部变量的地址,函数结束后,局部变量会被回收,返回的地址会指向一个不存在的地址。
  • 解决方法:
  • 创建一个全局变量,将局部变量的值赋给全局变量,返回全局变量的地址。
  • 使用 malloc 实现动态内存分配,返回分配的指针,注意释放内存。
  1. 数组名是地址常量,不能整体赋值
  • 使用 memcpy 等内存拷贝函数。
  • 字符数组使用 strcpy 函数。
  1. 未初始化导致“垃圾值”
  • 定义时立即初始化。int arr[10] = {0}; 可以将所有元素初始化为0。
  • 全局数组或静态数组(static)会被自动初始化为0。

二维数组常见陷阱

  1. 定义时不能省略列数
  • 在定义并初始化二维数组时,可以省略行数,但绝对不能省略列数。编译器需要知道列数来计算内存偏移,以正确访问元素。
  1. 函数传参时,列数必须明确

  2. 混淆行指针与二级指针

行指针是什么? 列指针是什么?

字符数组与字符串的专属陷阱

  1. 忘记字符串结束符 \0
  • 在字符数组中,字符串的结束符必须用 \0 来结束。如果没有结束符,那么字符串将无法被正确处理。
  1. 缓冲区溢出
  • 字符数组的大小必须足够大,以容纳字符串。如果字符串的长度超过字符数组的大小,那么字符串将无法被正确处理。
  • 注意: strncpy 在截断时不会自动添加 \0,需要手动添加。

常用字符数组函数

  • strcpy:将源字符串复制到目标字符串。
  • strncpy:将源字符串复制到目标字符串,最多复制 n 个字符。
  • strcat:将源字符串追加到目标字符串的末尾。
  • strncat:将源字符串追加到目标字符串的末尾,最多追加 n 个字符。
  • strlen:返回字符串的长度。
  • strcmp:比较两个字符串。
  • strncmp:比较两个字符串,最多比较 n 个字符。
  • strstr:在源字符串中查找子字符串。
  • strchr:在源字符串中查找字符。
  • strrchr:在源字符串中从末尾开始查找字符。
  • strspn: 该函数返回 str1 中第一个不在字符串 str2 中出现的字符下标。
  • strcpan: 该函数返回 str1 开头连续都不含字符串 str2 中字符的字符数。
> comment on / twitter
>
CC BY-NC-SA 4.0 2021-PRESENT © RYANUO