news 2026/4/24 22:31:02

C查漏补缺

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C查漏补缺

c语言基础

1,void func1(void);

普通函数声明,任意参数无返回值,需要实现函数体才能使用。

2,void *func2(void);

普通函数声明,任意参数返回任意函数指针,需要实现函数体才能使用。

3,void (*func3)(void);

函数指针声明,函数任意参数无返回值,属于变量声明,可以赋值。

4,void (*func4(void))(void);

函数指针声明,属于一个返回函数指针的函数指针,本体函数指针任意参数,返回的函数指针任意参数无返回值

5,fork使用

只会复制当前进程的调用fork的线程到子进程中。

6,c/c++可以看到0x0001u的用法

这个u表示unsigned,还有其他的一些修饰数字的前后缀,比如01中0表示8进制,1L中L表示long int , 1u中u表示unsigned int。

7,c语言中变量定义和赋值中逗号和分号的应用

结构体定义:内部用分号,结尾用分号。

枚举定义:内部逗号,结尾分号。

c++类定义:内部分号,结尾分号。

8,数组指针的部分误解

如果有int a[10];,那么a和&a表示相同的地址,但是代表不同的含义,a表示数组的首地址,&a表示数组大小为10的数组的地址。

也就是a+1表示a[1]的地址,但是&a+1表示a[10]的地址

常见应用如下:

①,指针的加减运算和整数的加减运算的差别

指针加减是变更n * sizeof(*p)

整数时变更n

比较维度指针算术运算整数算术运算
运算单位指向类型的大小为单位1为单位
示例p + n地址增加n * sizeof(*p)字节数值增加n
常见用途数组遍历、内存块操作普通数值计算
是否可跨类型不建议,会破坏对齐和访问规则不同类型可混合(隐式提升)
nullptr / 0不能对空指针解引用,但可加减 0正常数值 0
减法结果返回元素个数(ptrdiff_t),不是字节数返回数值差
合法性只能在同一数组或其后一位置范围内合法始终合法

9,当表达式中有有符号数据和无符号数据

一律将有符号转化为无符号。

这一点可能和向上转换原则不太一样,一般情况是小范围转大范围,但是有符号和无符号其实范围是一样的

10,结构体补齐规则

以前总是按照那3个准则来记忆,类似于:

对齐原则:每一成员的结束偏移量需对齐为后一成员类型的倍数

补齐原则:最终大小补齐为成员中最大值的倍数

有种方法更容易记忆。结构体成员以最大成员补齐,如果下个成员能填充到上个成员为对齐而空出的内容中的话,则这个成员会挤到上个成员会移到上个成员后的空位中

typedef struct A{ int a; //aaaa ***b cccccccc //如果没有b则a后仍空出4字节,b发现可以b的大小小于到4字节就会挤到空位中 char b; double c; }A; //16byte typedef struct B{ char b;//b*** aaaa cccccccc int a; double c; }B;//16byte typedef struct C{ int a;//aaaa**** cccccccc b******* double c; char b; }C;//24byte typedef struct D{ char b;//bbbbbbbb cccccccc aaaa**** double c; int a; }D;//24byte typedef struct E{ char b;//b*** aaaa c*** int a; char c; }E;//12byte

11,thread默认是非分离的

也就是如果thread_create后不进行thread_join,线程资源是不会释放的,一般可以手动设置detach,接下来线程结束后会自动释放,或者不设置detach,调用thread_join等待线程结束并释放资源。

12、头文件分类

stdlib.h:

getenv();atoi();abort();exit();free();malloc();

unistd.h:

getcwd();getpid();access();read();write();

ISO C标准定义的头文件(24项)

<assert.h> ---------------------- 验证程序断言

<complex.h> ---------------------- 支持复数算术运算

<ctype.h> ---------------------- 字符类型

<errno.h> ---------------------- 出错码

<fenv.h> ---------------------- 浮点环境

<float.h> ---------------------- 浮点常量

<inttypes.h> ---------------------- 整型格式转换

<iso646.h> ---------------------- 替代关系操作符宏

<limits.h> ---------------------- 实现常量

<locale.h> ---------------------- 局部类别

<math.h> ---------------------- 数学常量

<setjmp.h> ---------------------- 非局部goto

<signal.h> ---------------------- 信号

<stdarg.h> ---------------------- 可变参数表

<stdbool.h> ---------------------- 布尔类型和值

<stddef.h> ---------------------- 标准定义

<stdint.h> ---------------------- 整型

<stdio.h> ---------------------- 标准I/O库

<stdlib.h> ---------------------- 实用程序库函数

<string.h> ---------------------- 字符串操作

<tgmath.h> ---------------------- 通用类型数学宏

<time.h> ---------------------- 时间和日期

<wchar.h> ---------------------- 扩展的多字节和宽字符支持

<wctype.h> ---------------------- 宽字符分类和映射支持

POSIX标准定义的必须的头文件(26项)

<dirent.h> ---------------------- 目录项

<fcntl.h> ---------------------- 文件控制

<fnmatch.h> ---------------------- 文件名匹配类型

<glob.h> ---------------------- 路径名模式匹配类型

<grp.h> ---------------------- 组文件

<netdb.h> ---------------------- 网络数据库操作

<pwd.h> ---------------------- 口令文件

<regex.h> ---------------------- 正则表达式

<tar.h> ---------------------- tar归档值

<termios.h> ---------------------- 终端I/O

<unistd.h> ---------------------- 符号常量

<utime.h> ---------------------- 文件时间

<wordexp.h> ---------------------- 字扩展类型

<arpa/inet.h> ---------------------- Internet定义

<net/if..h> ---------------------- 套接字本地接口

<netinet/in.h> ---------------------- Internet地址族

<netinet/tcp.h>---------------------- 传输控制协议定义

<sys/mman.h>---------------------- 内存管理声明

<sys/select.h>---------------------- select函数

<sys/socket.h>---------------------- 套接字接口

<sys/stat.h> ---------------------- 文件状态

<sys/times.h> ---------------------- 进程时间

<sys/types.h> ---------------------- 基本系统数据类型

<sys/un.h> ---------------------- UNIX域套接字定义

<sys/utsname.h>----------------------系统名

<sys/wait.h> ---------------------- 进程控制

POSIX标准定义的XSI扩展头文件(26项)

<cpio.h> ---------------------- cpio归档值

<dlfcn.h> ---------------------- 动态链接

<fmtmsg.h> ---------------------- 消息显示结构

<ftw.h> ---------------------- 文件树漫游

<iconv.h> ---------------------- 代码集转换实用程序

<langinfo.h> ---------------------- 语言信息常量

<libgen.h> ---------------------- 模式匹配函数定义

<monetary.h> ---------------------- 货币类型

<ndbm.h> ---------------------- 数据库操作

<nl_types.h> ---------------------- 消息类别

<poll.h> ---------------------- 轮询函数

<search.h> ---------------------- 搜索表

<strings.h> ---------------------- 字符串操作

<syslog.h> ---------------------- 系统出错日志记录

<ucontext.h> ---------------------- 用户上下文

<ulimit.h> ---------------------- 用户限制

<utmpx.h> ---------------------- 用户帐户数据库

<sys/ipc.h> ---------------------- IPC

<sys/msg.h> ---------------------- 消息队列

<sys/resource.h>------------------- 资源操作

<sys/sem.h> ---------------------- 信号量

<sys/shm.h> ---------------------- 共享存储

<sys/statvfs.h>---------------------- 文件系统信息

<sys/time.h> ---------------------- 时间类型

<sys/timeb.h> ---------------------- 附加的日期和时间定义

<sys/uio.h> ---------------------- 矢量I/O操作

POSIX标准定义的可选头文件(8项)

<aio.h> ---------------------- 异步I/O

<mqueue.h> ---------------------- 消息队列

<pthread.h> ---------------------- 线程

<sched.h> ---------------------- 执行调度

<semaphore.h>--------------------- 信号量

<spawn.h> ---------------------- 实时spawn接口

<stropts.h> ---------------------- XSI STREAMS接口

<trace.h> ---------------------- 时间跟踪

What is glibc?

The GNU C Library project providesthecore libraries for the GNU system and GNU/Linux systems, as well as many other systems that use Linux as the kernel. These libraries provide critical APIs including ISO C11, POSIX.1-2008, BSD, OS-specific APIs and more. These APIs include such foundational facilities as open, read, write, malloc, printf, getaddrinfo, dlopen, pthread_create, crypt, login, exit and more.

The GNU C Library is designed to be a backwards compatible, portable, and high performance ISO C library. It aims to follow all relevant standards including ISO C11, POSIX.1-2008, and IEEE 754-2008.

The project was started circa 1988 and is more than 30 years old. You can see the complete project release history on the wiki.

Despite the project's age there is still a lot to do so please Get Started and Get Involved!

13、无符号类型和有符号类型进行算术运算和比较运算

相同值域范围时有符号转换为无符号, 不同值域范围时小范围转换位大范围

int aa = -1; unsigned int bb = 16; if (aa > bb) cout << "负数竟然大于正数了!\n";//实际aa转为无符号,大于bb

但是在算术运算时,无符号和有符号相加,结果一般也不会出什么问题,因为都是补码运算

unsigned int b = 1; int c = -1; printf("%d\n",c + b);//结果为0

14,16进制数据可以正数可以负数,

int a = -0x87654321;//error C4146: 一元负运算符应用于无符号类型,结果仍为无符号类型。原因是编译期首先将0x87654321赋予int,然后看到0x87654321大于INT_MAX,所以将0x87654321赋予unsigned int,然后看到前面有个负号,不能再讲unsigned转为有符号,所以报错

但是使用%x输出时会输出其补码(其实就是有符号转无符号的值),原因是%x默认是输出无符号16进制数据,%x和%0x意义一样,但是和%05x意义不一样。%x默认接受数据是unsigned int,先把数据转换位unsigned int再输出。

int a = -0x01; printf("%x,%d\n", a,a);// ;ffffffff,-1

可以看到0x87654321虽然超过了MAX_INT,但是使用补码可以存下来,输出的时候用%x可以原封不动输出

int a = 0x87654321; printf("%x,%d\n", a,a);// ;87654321,-2023406815

15、c语言符号

~表示按位取反

!表示逻辑取反

^表示按位异或,异或表示不同为1

16,printf家族:

printf表示格式化输入到标准输出中。

sprintf表示格式化输入到字符串中。

vprintf表示使用可变参数输入到标准输出。

vsprintf表示使用可变参数输入到字符串中。

vsnprintf表示使用可变参数输入到限制最大长度的字符串中。

17,__attribute__关键字用法和含义

__attribute__主要用于补充函数和变量的属性,比如限制函数参数类型,限制变量宽度等等,下面给出三个例子:

1,

extern int my_printf(void *my_object, const char *my_format, ...) __attribute__((format (printf, 2, 3))); //摘取printf的定义为 int printf(const char *format, ...) //archetype=printf:按照printf格式进行检查my_printf //string-index=2:my_printf的第2个参数(my_format)对应了printf参数中的format //first-to-check=3:my_printf的第3个参数(...)对应了printf参数中的...

2,

int y __attribute__((aligned (16))) = 0; char z[15] __attribute__((aligned (16))); //aligned应用于基础类型变量和数组时 //编译器对于基础类型变量和数组的编译原则如下: //系统默认按照变量类型本身占用内存的字节数来对齐边界(地址原则) //系统按照变量类型本身占用内存来分配内存字节数(内存原则) //通俗来讲,针对于基础类型变量和数组时,属性限定了变量存储的内存首地址,但是并没有影响变量实际占用 //内存的大小。

3,

typedef struct F1{ char i; int j[2] __attribute__((packed)); }F1_T; //9btyes typedef struct F2{ char i; int j[2] __attribute__((packed)); int k; }F2_T; //16btyes //系统应该为结构体成员按照最小的对齐方式来对齐边界(1bit或者1字节)

18,mmap使用方法

mmap主要作用是可以将外设硬件/flash等地址空间映射到当前进程的虚拟地址空间,从而可以通过内存操作来控制外设硬件/flash,常常用于外设驱动当中。

下面的例子是通过将一个文件映射到当前虚拟地址中,从而可以通过控制一块地址空间实现文件的读写。

#include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <unistd.h> int main() { int fd = open("./file.txt", O_RDWR);//读写权限 if(fd <= 0) { perror("\n"); return -1; } int len = lseek(fd, 0, SEEK_END);//读取文件大小 void* addr = mmap(NULL, len, PROT_WRITE, MAP_SHARED, fd, 0);//只有文件大小不为空时才能创建成功 if(addr == MAP_FAILED) { perror("mmap failed\n"); return -1; } close(fd);//内存映射成功后关闭文件描述符依然保持着映射 const char* str = "hello, world"; memcpy(addr, str, strlen(str)); return 0; }

此例子使用有以下点需要注意:

①:映射建立后可以关闭文件描述符

②:文件大小必须要大于0,并且文件大小映射后不能再改变

$ gcc test_mmap.c -o test_mmap $ touch file.txt $ echo "test123" > file.txt $ ./test_mmap $ cat file.txt $ hello wo

19,补码编码深入理解

原码到补码是一种映射

[-2^(n-1),2^(n-1)-1] 映射到------> [0,2^n]

正数的补码是原码,所以其实就是负数进行了映射[-2^(n-1),-1] -----> [2^(n-1),2^n-1],很容易看出映射公式:

补码=2^n+负数原码 (原码是负数)

补码=正数原码 (原码是正数)

根据这个映射原理,我们不再需要进行原码-反码-补码计算,而是进行原码-补码计算

例如:

1:求int a=-1的补码

补码=2^32-1=0xffffffff

2,int a=-1,求printf("%x",a);

%x默认输出无符号16进制,需要把有符号转化位无符号,我们知道计算机是以补码保存,所以其实就是原码转补码(原码是负数),再补码转原码(原码是正数,原码等于补码),所以最后求补码即可,补码2^32-1=0xffffffff

20,结构体位域

结构体位域表示使用此类型的多少位,如果相邻相同类型使用位数能挤进来,则挤进来。

struct test { int a:1; int b:1; int c:1; int d; };

sizeof(struct test) = 4+4=8

细节是:

abc0,0000,0000,0000,0000,0000,0000,0000

d

前面三个成员使用4个字节的前三位,后面的d使用单独的4个字节

20,scanf格式化输入

①格式化输入多个内容的时候,每个格式化输入内容前可以有无数个空格和换行

例如:

int a,b; sscanf("123\n\n\n\n456","%d%d",a,b);//找到第一个非空字符,为1,匹配到123,赋值给a,接下来找非空字符,为4,因此将456赋值给b printf("%d,%d\n",a,b);//a=123,b=456

②格式化字符含义

%d :int

%f:float

%lf:double

%c: char

%s:char *

%0X:unsigned int

%l:long

21,fgets和strtok的区别

fgets遇到换行和文件尾结束,strtok会修改原字符串

22,for循环表达式的执行顺序

for(a,b,c)d; //上述表达式执行顺序为a>b>d>c

注意d和c的顺序,d大于c

23,sscanf连续多个变量赋值

int a,b; sscanf("123 456","%d%d",&a,&b);//连续两个变量赋值时,指定字符串遇到空格/制表/换行时停止赋值,也就是123赋给a,456赋给b,返回值为赋值变量的个数,也就是2 sscanf("123,456","%d%d",&a,&b);//匹配的字符串有空格,也就是没有遇到空格/制表/换行,所以123赋值给a,b没有赋值,返回1

24,嵌套指针的使用

int a=0; int *b=&a; int **c=&b; *(*c)=1;//如果需要通过c来修改a,则需要双引用

25,数组作为函数入参时,可以不填数组大小

void func(int a[],int b[1]) { }

上述参数都允许的,实际调用时的数组是否越界得看具体编译器行为

26,fopen的参数含义

File fp=fopen("/home/test.txt","w");//只允许写,不允许读,文件不存在会创建,文件存在则清空 File fp=fopen("/home/test.txt","w+");//允许写,允许读,文件不存在会创建,文件存在则清空 File fp=fopen("/home/test.txt","r");//不允许写,允许读,文件不存在不会创建 File fp=fopen("/home/test.txt","r+");//允许写,允许读,文件不存在不会创建 File fp=fopen("/home/test.txt","a");//只允许写,不允许读,文件不存在会创建,文件存在则seek到文件末尾 File fp=fopen("/home/test.txt","a+");//允许写,允许读,文件不存在会创建,文件存在则seek到文件末尾

27,turboC2.0操作系统

turboC2.0是16位操作系统

28,类型转换

①,大值域向小值域的类型转换会进行截断

int a = -0x10001; short b = a; printf("%d\r\n", b);//-1

步骤 1:计算int a = -0x10001;

  1. 0x10001是十六进制,转十进制:0x10001 = 1*16⁴ + 0*16³ + 0*16² + 0*16¹ +1 = 65537

  2. 加上负号:a = -65537

  3. 计算机用补码存储,32 位 int 的补码为:0xFFFF FFFF

步骤 2:short b = a;核心截断

  1. short16 位有符号整数,赋值时会直接截取 int 的低 16 位

  2. 0xFFFF FFFF的低 16 位是:0xFFFF

  3. 16 位补码0xFFFF代表的十进制数就是-1

步骤 3:printf("%d\r\n", b);输出

  1. printf%d打印时,会把short类型符号扩展为 int

  2. 0xFFFF扩展为 32 位:0xFFFF FFFF,值还是-1

  3. 最终输出:-1

②,小值域向大值域的类型转换会进行符号扩展

short int a = -1; int b = a; printf("%d\r\n", b);//-1

步骤 1:short int a = -1;

  1. short int16 位有符号整数

  2. 十进制-1的 16 位补码是:1111 1111 1111 11110xFFFF

步骤 2:int b = a;核心:符号扩展

把 16 位short赋值给 32 位int时,有符号数会执行符号扩展

  • 看最高位(符号位):0xFFFF最高位是1(负数)

  • 高位全部补 1,扩展为 32 位:1111 1111 1111 1111 1111 1111 1111 11110xFFFFFFFF

  • 这个 32 位补码代表的数值依然是-1

步骤 3:printf("%d\r\n", b);

%d直接打印有符号 int,输出结果:-1

29,常量声明

①,单引号+字符

例如:'a'

②,单引号+转义

例如:‘\n’

③,单引号+8进制或者16进制转义

例如:8进制:‘\17’

16进制:‘\xff’

(注意没有十进制和二进制转义表示字符)

30,常见指针错误

①. 非法访问空指针

例如:

int *p=NULL; *p=0;

②. 非法访问野指针

int *p; *p=0;

③. 内存泄漏

int main() { void *p=malloc(1); return 0; }

30 内存拷贝

内存拷贝可能存在源地址和目的地址重叠的问题,遇到重叠的问题需要使用memmove方法,此方法会判断源地址和目的地址的高低,从而避免目的地址的数据覆盖了源地址的值

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/24 22:24:57

缝纫黑科技:泉州誉财对齐型旋转缝纫机专利抢先看

一、专利基础信息专利名称&#xff1a;一种对齐型的旋转缝纫机专利类型&#xff1a;发明专利申请号&#xff1a;202411720190.4申请日期&#xff1a;2024 年 11 月 28 日申请公布号&#xff1a;CN119265807A申请公布日&#xff1a;2025 年 01 月 07 日申请人&#xff1a;泉州誉…

作者头像 李华
网站建设 2026/4/24 22:22:50

GitHub API限流背后的机制与实战避坑:从匿名访问到OAuth App的完整策略

GitHub API限流机制深度解析与高并发场景优化策略 GitHub作为全球最大的代码托管平台&#xff0c;其API的稳定性直接影响着数百万开发者的日常工作流。当你深夜部署的CI/CD流水线突然中断&#xff0c;或是数据爬取脚本运行到一半戛然而止&#xff0c;控制台里赫然出现的"A…

作者头像 李华
网站建设 2026/4/24 22:21:35

YOLOv8架构精讲:从Backbone到Head的演进与实战

1. YOLOv8架构全景解析&#xff1a;从Darknet到C2f的进化之路 第一次看到YOLOv8的模型结构图时&#xff0c;我盯着那个像乐高积木一样拼接的Backbone发呆了十分钟——这和我熟悉的YOLOv5相比简直是脱胎换骨。作为从业多年的计算机视觉工程师&#xff0c;我决定带大家用"搭…

作者头像 李华
网站建设 2026/4/24 22:21:31

别乱用Logback异步日志!AsyncAppender配置里的queueSize和neverBlock踩坑实录

深入剖析Logback异步日志的配置陷阱与实战优化 最近在排查一个线上服务性能问题时&#xff0c;发现日志配置这个看似简单的环节竟然成了系统瓶颈。当时我们的订单服务在促销期间频繁出现响应延迟&#xff0c;经过层层排查&#xff0c;最终定位到问题出在Logback的异步日志配置上…

作者头像 李华