linux基础篇(一)——GCC和Makefile编译过程

2023-05-16

linux系列目录:

linux基础篇(一)——GCC和Makefile编译过程
linux基础篇(二)——静态和动态链接
ARM裸机篇(一)——i.MX6ULL介绍
ARM裸机篇(二)——i.MX6ULL启动过程
ARM裸机篇(三)——i.MX6ULL第一个裸机程序
ARM裸机篇(四)——重定位和地址无关码
ARM裸机篇(五)——异常和中断
linux系统移植篇(一)—— linux系统组成
linux系统移植篇(二)—— Uboot使用介绍
linux系统移植篇(三)—— Linux 内核使用介绍
linux系统移植篇(四)—— 根文件系统使用介绍
linux驱动开发篇(一)—— Linux 内核模块介绍
linux驱动开发篇(二)—— 字符设备驱动框架
linux驱动开发篇(三)—— 总线设备驱动模型
linux驱动开发篇(四)—— platform平台设备驱动


文章目录

    • linux系列目录:
  • 引入
  • GCC 编译工具链
  • GCC 编译器做了什么
    • GCC 编译过程
    • GCC基本语法
    • glibc库的作用
  • Makefile的引入
    • Makefile简介
  • 源码编译过程


引入

使用文本文件编写一个Hello World程序,文件名命名为hello.c:

#include <stdio.h>
int main()
{
	printf("Hello World\n");
	return 0;
}

然后我们如何使这个Hello World程序按我们预想的样子执行呢?平常我们都会使用各种集成开发环境(IDE),比如 Visual Studio、Keil等,这样的IDE一般都将编译和链接的过程一步完成,它们提供的默认配置、编译和链接参数对我们日常使用而言已经足够了,但是我们往往也会被这些复杂的集成工具所提供的强大功能所迷惑,很多系统软件的运行机制与机理被掩盖。

接下来请思考以下几个问题:

  • #include <stdio.h>是什么意思?把stdio.h包含进来意味着什么?
  • 为什么要有mian函数?程序为什么会从main函数开始运行?
  • printf是怎么实现的?它为什么可以在终端显示?
  • return 0意味着什么?return以后程序跑到哪了?

看似简单的一个Hello World程序想要运行起来,背后其实隐藏了大量的细节,Hello World程序从源代码到变成可执行文件的一个简单流程大概如下图所示:
编程步骤

源代码大家都已经比较熟悉了,接下来我会通过几篇文章来简单的介绍一下剩下步骤和使所使用到的工具,并尝试挖掘出Hello World程序背后隐藏的细节。

GCC 编译工具链

GCC 编译工具链(toolchain)是指以 GCC 编译器为核心的一整套工具,用于把源代码转化成可执行应用程序。它主要包含以下三部分内容:
• GCC 编译器 : 用于完成预处理和编译过程,例如把 C 代码转换成汇编代码。
• glibc:包含了主要的 C 语言标准函数库, C 语言中常常使用的打印函数 printf、 malloc 函数就在 glibc 库中。
• Binutils :除GCC编译器外的一系列小工具包括了链接器ld,汇编器as、目标文件格式查看器readelf等。

GCC 编译器做了什么

从直观的角度讲,编译器就是把高级语言翻译成机器语言的一个工具。编译过程一般可以分为6步:词法分析、语法分析、语义分析、源代码优化、目标代码生成与优化。

  • 词法分析:将源代码运用一种类似有限状态机的算法把代码的字符序列分割成一些列的记号,比如关键字、标识符、特殊符号等。
  • 语法分析:将有词法分析产生的记号进行语法分析,从而产生语法树。
  • 语义分析:对静态语义进行分析,通常包括声明和类型匹配,类型的转换,经过语义分析后,整个语法树的表达式都将被标识了类型。
  • 源码优化:源代码优化器将整个语法树转换成中间代码,中间代码已经非常接近目标代码了,但是它一般与目标机器和运行时环境无关。
  • 目标代码生成与优化:代码生成器将中间代码转换成目标机器代码,最后目标代码优化器对上述目标代码进行优化。

中间代码使得编译器可以分为前端和后端。编译器前端负责产生机器无关的中间代码,编译器后端将中间代码转换成目标机器代码。

我们通常说的GCC是一套完整的编译器软件,包括编译器前端和后端。

常见的编译器前端和后端如下图所示:

编译器编译器前端编译器后端
GCC编译器GCCGCC
LLVM-GCC编译器GCCLLVM
LLVM编译器ClangLLVM

GCC for ARM 则是基于 GCC 开发的,用来编译生成 ARM 内核可执行文件的编译套件,俗称 ARM 交叉编译套件
ARM 交叉编译工具链的命名规则:

arch [-vendor] [-os] [-(gnu)eabi] [-gcc]
在这里插入图片描述

如果同时没有 vendor 和 os 支持,则只用一个 none 代替。

GCC 编译过程

linux系统默认安装了GCC 编译工具链,当我们使用GCC来编译Hello World程序时,只需要使用简单的命令:

> gcc hello.c -o hello
> ./hello
Hello World

事实上,上述过程可以分解为4个步骤,分别是预处理、编译、汇编和链接
如图所示:
请添加图片描述

GCC基本语法

gcc [选项] 文件名
在这里插入图片描述

  • (1)预处理
    C/C++源文件中,以#开头的命令被称为预处理命令,如"#include"、宏定义命令"#define"、条件编译命令"#if、#ifdef"等。预处理是将包含(include)的文件插入原文件中、将宏定义展开、根据条件编译命令选择要使用的代码,最后将这些东西输出到一个.i文件中并等待进一步处理。
    我们对hello只进行预处理:
> gcc -E hello.c -o hello.i

打开hello.i可以发现#include <stdio.h>已经被相关内容给替换掉了。

  • (2)编译
    编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生产相应的汇编代码文件。
#对hello.i进行编译:
> gcc -S hello.i -o hello.s

打开hello.s,可以看到编译完成后生成的便是汇编代码。

  • (3)汇编
    汇编就是将第二步输出的汇编代码翻译成符合一定格式的机器代码,在Linux系统上一般表现为ELF目标文件(OBJ文件)。反汇编是指将机器代码转换为汇编代码,这在调试程序时常常用到。
    可以使用如下命令生成:
> gcc -c hello.s -o hello.o
  • (4)链接
    链接通俗讲就是将上步生成的OBJ文件和系统库的OBJ文件、库文件链接起来,最终生成可以在特定平台运行的可执行文件。
    链接是一个比较复杂的过程,链接可以在编译时由静态编译器来完成 ,也可以在加载时和运行时由动态链接器来完成 。
    Hello World程序的printf便是有glibc中的库文件定义的,再下篇文章中再专门介绍库文件和链接过程。

glibc库的作用

hello.c的第一行代码#include <stdio.h>,经过gcc -E hello.c -o hello.i后,#include <stdio.h>被替换掉了。
我们知道printf函数的声明是在stdio.h这个头文件中,那么gcc是怎么找到stdio.h这个头文件的呢,换句话说stdio.h这个头文件在系统的什么地方?
还有hello.c的第二行代码int main(),为什么一定要写成main才行?
这些问题都与glibc库和链接有关,下一节来专门讲解glibc库和链接。

Makefile的引入

只有一个hello.c文件,非常简单,所以直接执行下面的指令进行编译也非常方便。

> gcc hello.c -o hello
> ./hello
Hello World

但是实际上一个工程不可能只有一个文件,当一个工程中有很多C源文件和H头文件时,再直接使用编译器指令就非常麻烦了,比如编译多个文件:

gcc hello.c aaa.c bbb.c -o hello

而且哪怕你只是修改一个文件,也需要重新编译所有的文件,白白浪费了很多开发时间。 要解决这个问题,最好的方式就是把工程的编译规则写下来,让编译器自动加载该规则进行编译。 解决方法就是使用make和Makefile,这两个工具是搭配使用的:

  • make工具:它可以帮助我们找出项目里面修改变更过的文件,并根据依赖关系,找出受修改影响的其他相关文件,然后对这些文件按照规则进行单独的编译,这样一来,就能避免重新编译项目的所有的文件。

  • Makefile文件:上面提到的规则、依赖关系主要是定义在这个Makefile文件中的,我们在其中合理地定义好文件的依赖关系之后,make工具就能精准地进行编译工作。

Makefile简介

我们管理一个项目工程,实质上就是管理项目文件间的依赖关系。 所以我们在学习和使用Makefile的时候,一定要牢牢抓住它这种面向依赖的思想, 心里一定要谨记,Makefile中所有的复杂、晦涩的语法都是更好地为解决依赖问题而存在的。
关于Makefile的详细使用可参考《跟我一起写Makefile》一书或GNU官方的make说 明文档:https://www.gnu.org/software/make/manual
野火的在线文档已经把如何快速使用Makefile讲解的比较清楚,我这里就不再重复了,可以进入链接学习:
https://doc.embedfire.com/linux/imx6/base/zh/latest/linux_app/makefile.html

源码编译过程

源码要运行,必须先转成二进制的机器码。这是编译器的任务。
比如,下面这段源码:

#include <stdio.h>
int main()
{
	printf("Hello World\n");
	return 0;
}

要先用编译器处理一下才能运行,编译步骤如下:

> gcc hello.c -o hello
> ./hello
Hello World

对于复杂的项目,编译过程还必须分成三步。

> ./configure
>  make  
>  make install

第一步 配置(configure)

编译器在开始工作之前,需要知道当前的系统环境,比如标准库在哪里、软件的安装位置在哪里、需要安装哪些组件等等。这是因为不同计算机的系统环境不一样,通过指定编译参数,编译器就可以灵活适应环境,编译出各种环境都能运行的机器码。这个确定编译参数的步骤,就叫做"配置"(configure)。
这些配置信息保存在一个配置文件之中,约定俗成是一个叫做configure的脚本文件。通常它是由autoconf工具生成的。编译器通过运行这个脚本,获知编译参数。

configure脚本已经尽量考虑到不同系统的差异,并且对各种编译参数给出了默认值。如果用户的系统环境比较特别,或者有一些特定的需求,就需要手动向configure脚本提供编译参数:

$ ./configure --prefix=/www --with-mysql

上面代码是php源码的一种编译配置,用户指定安装后的文件保存在www目录,并且编译时加入mysql模块的支持。

第二步 确定标准库和头文件的位置

源码肯定会用到标准库函数(standard library)和头文件(header)。它们可以存放在系统的任意目录中,编译器实际上没办法自动检测它们的位置,只有通过配置文件才能知道。

编译的第二步,就是从配置文件中知道标准库和头文件的位置。一般来说,配置文件会给出一个清单,列出几个具体的目录。等到编译时,编译器就按顺序到这几个目录中,寻找目标。

第三步 确定依赖关系

对于大型项目来说,源码文件之间往往存在依赖关系,编译器需要确定编译的先后顺序。假定A文件依赖于B文件,编译器应该保证做到下面两点。
(1)只有在B文件编译完成后,才开始编译A文件。

(2)当B文件发生变化时,A文件会被重新编译。

编译顺序保存在一个叫做makefile的文件中,里面列出哪个文件先编译,哪个文件后编译。而makefile文件由configure脚本运行生成,这就是为什么编译时configure必须首先运行的原因。

在确定依赖关系的同时,编译器也确定了,编译时会用到哪些头文件。
第四步 头文件的预编译(precompilation)

不同的源码文件,可能引用同一个头文件(比如stdio.h)。编译的时候,头文件也必须一起编译。为了节省时间,编译器会在编译源码之前,先编译头文件。这保证了头文件只需编译一次,不必每次用到的时候,都重新编译了。

不过,并不是头文件的所有内容,都会被预编译。用来声明宏的#define命令,就不会被预编译。

第五步 预处理(Preprocessing)

预编译完成后,编译器就开始替换掉源码中bash的头文件和宏。以本文开头的那段源码为例,它包含头文件stdio.h,替换后的样子如下。

    extern int printf(const char *, FILE *);
    
    int main(void){
    
    	printf("Hello World\n");
        return 0;
    }

为了便于阅读,上面代码只截取了头文件中与源码相关的那部分,即fputs和FILE的声明,省略了stdio.h的其他部分(因为它们非常长)。另外,上面代码的头文件没有经过预编译,而实际上,插入源码的是预编译后的结果。编译器在这一步还会移除注释。

这一步称为"预处理"(Preprocessing),因为完成之后,就要开始真正的处理了。
第六步 编译(Compilation)

预处理之后,编译器就开始生成机器码。对于某些编译器来说,还存在一个中间步骤,会先把源码转为汇编码(assembly),然后再把汇编码转为机器码。

下面是本文开头的那段源码转成的汇编码。

  .file   "test.c"
    .section    .rodata.LC0:
    .string "Hello, world!\n"
    .text    .globl  main    .type   main, @functionmain:.LFB0:
    .cfi_startproc
    pushq   %rbp    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp    .cfi_def_cfa_register 6
    movq    stdout(%rip), %rax
    movq    %rax, %rcx
    movl    $14, %edx
    movl    $1, %esi
    movl    $.LC0, %edi
    call    fwrite
    movl    $0, %eax
    popq    %rbp    .cfi_def_cfa 7, 8
    ret    .cfi_endproc.LFE0:
    .size   main, .-main    .ident  "GCC: (Debian 4.9.1-19) 4.9.1"
    .section    .note.GNU-stack,"",@progbits

这种转码后的文件称为对象文件(object file)。
第七步 链接(Linking)

对象文件还不能运行,必须进一步转成可执行文件。如果你仔细看上一步的转码结果,会发现其中引用了stdout函数和fwrite函数。也就是说,程序要正常运行,除了上面的代码以外,还必须有stdout和fwrite这两个函数的代码,它们是由C语言的标准库提供的。

编译器的下一步工作,就是把外部函数的代码(通常是后缀名为.lib和.a的文件),添加到可执行文件中。这就叫做连接(linking)。这种通过拷贝,将外部函数库添加到可执行文件的方式,叫做静态连接(static linking),后文会提到还有动态连接(dynamic linking)。

make命令的作用,就是从第四步头文件预编译开始,一直到做完这一步。
第八步 安装(Installation)

上一步的连接是在内存中进行的,即编译器在内存中生成了可执行文件。下一步,必须将可执行文件保存到用户事先指定的安装目录。

表面上,这一步很简单,就是将可执行文件(连带相关的数据文件)拷贝过去就行了。但是实际上,这一步还必须完成创建目录、保存文件、设置权限等步骤。这整个的保存过程就称为"安装"(Installation)。
第九步 操作系统连接

可执行文件安装后,必须以某种方式通知操作系统,让其知道可以使用这个程序了。比如,我们安装了一个文本阅读程序,往往希望双击txt文件,该程序就会自动运行。

这就要求在操作系统中,登记这个程序的元数据:文件名、文件描述、关联后缀名等等。Linux系统中,这些信息通常保存在/usr/share/applications目录下的.desktop文件中。另外,在Windows操作系统中,还需要在Start启动菜单中,建立一个快捷方式。

这些事情就叫做"操作系统连接"。make install命令,就用来完成"安装"和"操作系统连接"这两步。
第十步 生成安装包

写到这里,源码编译的整个过程就基本完成了。但是只有很少一部分用户,愿意耐着性子,从头到尾做一遍这个过程。事实上,如果你只有源码可以交给用户,他们会认定你是一个不友好的家伙。大部分用户要的是一个二进制的可执行程序,立刻就能运行。这就要求开发者,将上一步生成的可执行文件,做成可以分发的安装包。

所以,编译器还必须有生成安装包的功能。通常是将可执行文件(连带相关的数据文件),以某种目录结构,保存成压缩文件包,交给用户。
第十一步 动态连接(Dynamic linking)

正常情况下,到这一步,程序已经可以运行了。至于运行期间(runtime)发生的事情,与编译器一概无关。但是,开发者可以在编译阶段选择可执行文件连接外部函数库的方式,到底是静态连接(编译时连接),还是动态连接(运行时连接)。所以,最后还要提一下,什么叫做动态连接。

前面已经说过,静态连接就是把外部函数库,拷贝到可执行文件中。这样做的好处是,适用范围比较广,不用担心用户机器缺少某个库文件;缺点是安装包会比较大,而且多个应用程序之间,无法共享库文件。

动态连接的做法正好相反,外部函数库不进入安装包,只在运行时动态引用。好处是安装包会比较小,多个应用程序可以共享库文件;缺点是用户必须事先安装好库文件,而且版本和安装位置都必须符合要求,否则就不能正常运行。

现实中,大部分软件采用动态连接,共享库文件。这种动态共享的库文件,Linux平台是后缀名为.so的文件,Windows平台是.dll文件,Mac平台是.dylib文件。
参考文章:
gcc&arm-linux-gcc编译过程详解

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux基础篇(一)——GCC和Makefile编译过程 的相关文章

  • 用户身份认证

    0 背景 计算机本身无法判断坐在显示器前的使用者的身份 xff0c 也无法确认网络的另一端的是谁 为了明确是谁在访问服务器 xff0c 必须让客户端自报家门 通常核对一些登录者本人的信息 xff1a 密码 xff1a 只有本人知道的字符串信
  • 一款用过就舍不得换的播放器-potplayer(中文绿色版)/win64

    PotPlayer 是 KMPlayer 的原制作者姜龙喜先生 xff08 韩国 xff09 进入 Daum 公司后的新一代网络播放器 PotPlayer 的优势在于强大的内置解码器 xff1b 而 KMPlayer 的优势在于强大的定制能
  • (一) odroid-xu4交叉编译过程

    目录 文章目录 目录前言Toolchain安装过程总结 前言 现在转到ODROID xu4的平台 xff0c 需要安装ODROID xu4的交叉编译环境 xff0c 特此记录 xff01 本文参照ODROID Wiki Toolchain安
  • 使用OPENMV控制云台自动追踪Apriltag,测出与Apriltag距离并且通过串口发送给单片机。

    使用openmv控制云台自动跟踪Apriltag xff0c 并且将openmv与Apriltag距离通过串口发送到单片机 如果有openmv的同学直接将main py和pid py复制到flash中就可以了 注意 xff01 Aprilt
  • ubuntu 配置http

    1 去服务器上购买免费https服务并配置域名等 2 根据自己的网站服务器来选择下载不同的ssl证书 apache证书包括 1 root bundle crt 证书文件 2 xxx xxx xxx crt 证书文件 3 xxx xxx xx
  • C++中istringstream、ostringstream、stringstream详细介绍和使用

    C 43 43 中istringstream ostringstream stringstream介绍和使用 1 基于控制台的I O 注意 xff1a 提取符 34 gt gt 从流中提取数据时跳过输入流中的空格 tab键 换行符等空白字符
  • java httpClient Digest Auth 认证

    技术交流QQ群 933925017 java httpClient Digest Auth 认证 因为项目需要 请求海康摄像头 进行抓图以及云台控制等功能 海康有http协议 但是需要进行请求头认证 因为海康给的资料已经过时 所以找了很久
  • 锂电池充电过程及电路设计

    通常为了提高电池充电时的可靠性和稳定性 xff0c 我们会用电源管理芯片来控制电池充电的电压与电流 xff0c 但是在使用电源管理芯片设计充电电路时 xff0c 我们往往对充电电路每个时间段的工作状态及电路设计注意事项存在一些困惑 1 电池
  • 0Ω电阻到底能过多大电流

    0 电阻到底能过多大电流 xff1f 这个问题想必每位硬件工程师都查过 而与之相关的还有一个问题 xff0c 那就是0 电阻的阻值到底有多大 xff1f 这两个问题本来是很简单的 xff0c 答案应该也是很明确的 xff0c 但网上网友却给
  • linux进程控制函数--fork,exec,exit,wait,sleep

    1 fork 在linux系统中 xff0c 用户创建进程的唯一方法就是使用系统调用fork xff0c 大概要进行下面的操作 lt 1 gt 分配表项 xff0c 一个用户的进程项是有限的 xff1b lt 2 gt 创建子进程的进程标识
  • linux的用户模式和内核模式

    MS DOS等操作系统在单一的CPU模式下运行 xff0c 但是一些类Unix的操作系统则使用了双模式 xff0c 可以有效地实现时间共享 在Linux机器上 xff0c CPU要么处于受信任的内核模式 xff0c 要么处于受限制的用户模式
  • 阿里内推面试经历

    写在最前 其实主观上并不是很想写 xff0c 但坚持写完是希望能分享给准备进互联网实习或工作的同学或朋友一些经验和收获
  • 关于利用Openmp中使用的时间函数

    Openmp是一项并行化技术 xff0c 是可以提高串行化程序的运行效率的 xff0c 但需要使用正确的时间函数来进行衡量 首先 xff0c 先提出一个unix linux下的内核时间获取函数和一个omp h的一个库函数 1 clock 函
  • mybatis之映射文件

    mybatis框架如何实现java语句与数据库语句的分离 映射文件 通过在映射文件中写入动态sql语句 xff0c 完成增删改查操作 映射文件中的元素都包含在根节点 lt mapper gt lt mapper gt 下 xff0c map
  • mybatis之高级查询

    Mybatis中的高级查询主要通过关联查询 xff0c 集合查询或鉴别器来完成 其核心就是之前提到的通过resultMap标记来完成 1 关联查询 关联查询一般有三种方式 xff1a a 联合查询 利用resultMap的map xml中的
  • mybaits之动态sql

    mybaits除了提供连接数据库 xff0c 使java和数据库语句分离之外 xff0c 还有一个显著的特点就是使用动态sql语句 这些sql语句均写在map映射文件中 xff0c 并通过一系列标记来完成 1 if标记 常用形式 xff1a
  • 平衡二叉树-的四种旋转调整(代码,图解)

    平衡二叉树 的四种旋转调整 xff08 代码 xff0c 图解 xff09 1 右单旋 xff1a 新插入节点插入在较高左子树的左侧 xff08 左左右 xff09 xff0c 插入新节点二十 xff1a 1 修改parent和curLR的
  • 头文件里一般会加入的宏定义,为了避免一个头文件被重复调用

    华清视频里讲的 xff0c 写代码的时候 xff0c 头文件一般地都会加上一个类似这样的宏 xff0c 希望你从此以后再写头文件 xff0c 加上一个宏 加了这个有一个好处 xff0c 当你第一次包含tree h的时候 xff0c 如果没定
  • 自己组装Pixhawk F450无人机的一些细节

    首先参考文档为 xff1a 1 https mp weixin qq com s VXKU kIB v i0AX3zgtLig 2 https mp weixin qq com s Qzzl dQ6Tz2pXNp7Oj0lTg 3 http
  • 电机和桨叶要搭配选择

    拍自 四旋翼无人机的制作与飞行

随机推荐

  • 接收机PPM与SBUS

    最开始是自己弄ACfly的飞控时发现插接收机有两个位置 xff0c 一个PPM一个SBUS xff0c 我想直接移植Pixhawk的接收机或者无名的接收机到ACfly模块上 我最后发现Pixhawk和无名的也是留了两个给接收机 xff08
  • 现在发现如果无人机的电机不同,浆可能是不能混用的。

    现在发现如果无人机的电机不同 xff0c 浆可能是不能混用的 孔位不同 xff0c 我之前在无名那里买了很多浆 xff0c 觉得这次F330的浆没了可以用那个替 xff0c 我刚刚试了下发现插不进去 xff0c 不能通用 包括我刚才在店家那
  • 无人机电池似乎可以并联,串联组合

    之前总是见到这种奇怪的线 xff0c 一直不知道作什么用 xff0c 现在大概清楚了 是不是这样可以实现更长时间的续航 xff0c 我之前再ACfly的群里看到一个人的六轴是上面放了两个电池的 xff0c 他这可能也是并联的
  • 任务的三要素是任务主体函数,任务栈和任务控制块

    任务的三要素是任务主体函数 xff0c 任务栈和任务控制块 由xTaskCreateStatic 函数来把三者联合起立 下面拍自野火的 FreeRTOS内核实现与应用开发实战指南
  • 如何用Realsense D435i运行VINS-Mono等VIO算法 获取IMU同步数据

    摘自 xff1a https blog csdn net qq 41839222 article details 86552367 如何用Realsense D435i运行VINS Mono等VIO算法 获取IMU同步数据 Manii 20
  • Opencv安装与环境配置

    转载自 xff1a https blog csdn net sm16111 article details 81238324 Opencv安装与环境配置 代码敌敌畏 2018 07 27 15 46 24 50411 收藏 94 分类专栏
  • 串口参数详解:波特率,数据位,停止位,奇偶校验位

    转载自 xff1a https blog csdn net sinat 35705952 article details 89034455 串口参数详解 xff1a 波特率 xff0c 数据位 xff0c 停止位 xff0c 奇偶校验位 W
  • cpp-httplib库简单原理,听说你还不会开源库?

    cpp httplib库的原理 听说你还不会开源库 xff1f 介绍httplib h头文件的处理流程httplib h头文件的组成httplib h头文件搭建服务端与客户端的原理Get接口listen 0 0 0 0 8989 接口 介绍
  • UART串口调试

    转载自 xff1a https www secpulse com archives 157847 html UART串口调试 脉搏文库 TideSec 2021 04 23 4 356 0x00前言 前段时间陆陆续续的对光猫 路由器 摄像头
  • visca协议及其实现的简单认识

    转载自 xff1a https latelee blog csdn net article details 35811777 visca协议及其实现的简单认识 李迟 2014 06 30 14 09 01 7064 收藏 12 分类专栏 x
  • C语言实现的一个简单的HTTP程序

    转载自 xff1a https www cnblogs com xuwenmin888 archive 2013 05 04 3059282 html C语言实现的一个简单的HTTP程序 以下是参考 lt winsock网络编程经络 gt
  • ideavim使用

    IdeaVim 常用操作 IdeaVim简介 IdeaVim是IntelliJ IDEA的一款插件 xff0c 他提高了我们写代码的速度 xff0c 对代码的跳转 xff0c 查找也很友好 安装之后它在 Tools gt Vim Emula
  • CAN总线——数据传输故障处理

    最近遇到CAN总线通讯的问题 上位机为arm板 xff0c 核心板为Cortex A9处理器 Linux内核 下位机为5块 STM32板 现象为 xff1a 如果上位机只接收数据 xff0c 一切通讯正常 当上位机下发命令 xff0c 那么
  • 升级构建工具,从Makefile到CMake

    更多博文 xff0c 请看音视频系统学习的浪漫马车之总目录 C C 43 43 编译 浅析C C 43 43 编译本质 一篇文章入门C C 43 43 自动构建利器之Makefile 升级构建工具 xff0c 从Makefile到CMake
  • RTKLIB简介

    RTKLIB是全球导航卫星系统GNSS global navigation satellite system 的标准 amp 精密定位开源程序包 xff0c RTKLIB由日本东京海洋大学 xff08 Tokyo University of
  • zzuli OJ 1038: 绝对值最大

    Description 输入3个整数 xff0c 输出绝对值最大的那个数 Input 输入包含3个int范围内的整数 xff0c 用空格隔开 Output 输出三个数中绝对值最大的数 xff0c 单独占一行 若绝对值最大的数不唯一 xff0
  • md5sum

    ERROR 1550456422 414780061 Client Lidar cipv 213 wants topic rs percept result to have datatype md5sum autodrive msgs Pe
  • libcurl实现HTTP

    关于libcurl的相关函数介绍以及参数详见官方说明 https curl haxx se libcurl c example html HTTP Request 一个http请求包含方法 路径 http版本 请求包头 请求方法 GET H
  • 深夜没事,抓个ARP包吧!

    深夜没事 xff0c 抓个ARP包吧 xff01 ipconfig查看网卡信息 选择en33这个网卡 xff0c 发送两次 xff0c 询问192 168 21 1的mac地址 xff0c 注意 xff1a ARP请求只能在同一子网内部进行
  • linux基础篇(一)——GCC和Makefile编译过程

    linux系列目录 xff1a linux基础篇 xff08 一 xff09 GCC和Makefile编译过程 linux基础篇 xff08 二 xff09 静态和动态链接 ARM裸机篇 xff08 一 xff09 i MX6ULL介绍 A