嵌入式学习系列之Linux基础、C语言高级基础知识,本篇主要讲述了Linux基本操作,以及C高级基础知识,Linux基本操作主要涉及到Linux基本命令及使用、链接文件、通配符和网络配置、shell基础知识等,C高级包括gdb调试、指针、递归等,都是用于嵌入式基础巩固。
整篇是本人通过学习进行笔记记载,如有不足,还请不要吝啬指出。另外我们提供嵌入式项目毕设资料与服务,远程部署、代码讲解、全方位服务。我们有专门的毕设项目辅导群(QQ:596557438)!!!
资料及项目下载地址:箫声商城
一、Linux基础
1.Linux基础知识和使用
裸机开发:只有裸硬件,没有Os(operation system操作系统),把开发板当做单片机玩,汇编+c语言
底层的开发:有硬件,也有os(80%都会选择Linux)driver:驱动,C语言
上层的开发:C\C++:超集(QT)\JAVA(Android)
GPI:开源软件:免费使用/衍生版本/免费提供源代码(开源、免费、修改后必须免费)
Linux:狭义(kernel内核)、广义=狭义+很多app应用程序L
Long term support 长期支持
2.操作系统的组件
1)Linux内核:kernel.org
2)Shell
3)文件系统
4)实用程序
Linux内核:
支持多用户(multi user)、多任务(multi 模式运行;Shell是一个命令行解释器,它使得用户能够与操作系统相连接;
Deb软件包(Ubuntu)/Rpm软件包(红帽)
3.如何安装Linux应用程序
Linux卸载软件有两种方法:
1.dpkg:
dpkg -i(install)后跟安装包的文件名<package> 用来安装
sudo 首先要下载应用软件安装包
凡是ubuntu中软件文件名后缀都是.deb,软件名_版本号—次版本号_amd64(体系结构).deb/i386(安装在32位系统)
dpkg -r(remove)<package> 用来移除,即卸载
sudo(用管理员身份执行) dpkg -r存在两个问题:
①需要先下载安装包
②无法处理依赖:
A软件依赖于B软件:A软件需要用到B软件的东西,如果不先装B软件,那么A软件就不能安装成功,或者运行成功
apt-cache depends vim 可查看依赖于那些软件
配置文件
软件源,直接拷贝到sources.deak
2.apt:
sudo apt-get install vim(安装) sudo apt-get install --reinstall(重新安装)
cd /etc/apt/ -> vim sources.list 需要提醒的是,在每次修改完/etc/apt/sources.list文件后,一定要运行“apt-get update“命令,才会使更改有效。
可以自动处理依赖
sudo apt-get remove vim(卸载)
3.update :下载更新软件包列表信息
sudo apt-get update :很长时间未安装,进行刷新更新
/etc/apt/sources.list
4.clean :删除缓存区中所有已下载的包文件
/var/cache/apt/archieve/xxx.deb 缓存
apt-get clean
5.reverse 反转
apt-cache policy vim(已经安装,且告知相应信息,查看软件安装状态)
4.开机与关机
开机与重启
sudo shutdown (关闭) -h +1(定时关机) now
-r now (重启)
5.Shell命令格式
命令提示符(shell:命令行解释器(将用户的命令翻译成机器看得懂的语言)):
当前用户名@主机名:目录名
用户名:显示当前登录用户的账户名
主机名:显示登录的主机名
目录名:显示当前所处的路径,当在根目录下显示为“/”,当在用户名目录下显示“~”。
命令格式:
指令 选项 参数
"$"是Shell提示符,如果当前用户
注意:
1.一条命令的三要素之间用空格隔开;
2.若将多个命令在一行书写,用分号(;)将各命令隔开;
3.如果一条命令不能在一行写完,在行尾使用反斜杠(\)标明该条命令未结束。
6. Linux根文件系统
以根目录为主向下呈分枝状的结构文件的存储位置有要求
bin:存放二进制文件,可执行程序
etc:配置目录
lib:库目录
boot:启动引导目录
root:超级用户目录
home:家目录
dev:设备目录
Linux下一切皆文件(Lsp-bcd)
L:连接文件
S:套接字文件
P:管道文件
—:普通文件:.c文件、txt文件
B:块设备
C:字符设备
D:目录文件
7. Linux的基本命令
history:查看我所执行的历史命令
ls : 列出文件名 ls /文件名 查看该文件目录下的内容
ls -l -d 文件,以.开头文件被称为隐藏文件:ls -acat : 显示文本文件内容
gedit:打开文本编辑
less/more: 分屏显示文件 more 使用时:翻页按空格,翻行用回车,退出按q,后翻按b;
rm(remove): 删除文件
cp: 复制文件
mv: 移动文件/重命名
mkdir: 创建目录 -p:没有父目录,创建子目录
rmdir: 删除空目录///rm 文件名 -r(recursive)递归 //能删除有文件的目录
clear : 清屏
touch : 建立空文件/ 刷新时间戳
pwd : 显示当前在那个目录下
.. : 返回上一个目录
cd : 改变当前所在的目录/切换目录 ~(家目录)
grep : 查找字符串 ,在指定的位置搜索内容含有特征的文件
grep 'love'/"love" ~/文件名 -R -lfind: 查找关键词文件名:find ~/具体文件名 -name ‘love*'文件名特征 *代表0个或任意个
head : 显示文件开头
tail : 显示文件结尾
sort : 按次序显示文件
uniq : 去掉文件中相邻重复的行
diff :比较两个文件
cmp :比较两个文件的不同
file :查看文件类型
whoami : 查看当前用户是谁
/ : cd / 切换到根目录(相当于windows的我的电脑)
:父目录与子目录的分隔符echo (回音、回声): 显示文本,换行, -n(不换行)
date : 显示时间和日期,还可以修改时间
修改时间 :sudo date -s
gzip : 压缩文件gunzip: 解压缩文件
bzip2 : 压缩文件
tar : 归档和展开文件,打包(cf:create file创建文件)、解包(xf:extract file 提取),非压缩
tar czf yangzhu.tar.gz(一次性打包压缩) -cvf
tar xzf yangzhu.tar.gz(一次性解压缩) -zcvfwhereis : 查找命令
which : 查找实用程序
ps : 列出进程(指程序的一次运行)前台进程(看的见)/后台进程(看不见的)
tty ps -t pts/0
ps aux 当前所有进程
ps aux | wc -l 统计行数,总计-1
ps -l(long) :ps进程是由bash进程生下来的(称bash是ps的父进程) PPID
ps -p PID -l
pstree (进程树)df(disk free) : 检查文件系统空间占用情况
du : 显示目录空间的使用情况 -h:human readable (人类可读)
Kill : 杀死进程 kill -9 ....强制杀死
chmod : 改变文件或目录的访问权限
chown : 改变文件或目录的属主 sudo chown xxx:xxx,可修改属主名
chgrp : 改变文件或目录所属的组 sudo chown xxx:xxx
info : 获得帮助
rpm : rpm包管理工具
In : 创建文件链接
who : 列出系统上用户名单
write : 发送消息
talk : 与其他用户通信
man : 获取帮助(manual: 手册)
gcc:编译 gcc 1.c / gcc 1.c -o app 给可执行文件重命名
passwd :重置密码;只有管理员才能重置其他用户的密码
passwd (root)
su : 切换用户身份
su root 切换到root的密码exit :退回原来用户
用户管理:
属性:
用户名
口令
用户ID(UID)adduser:创建新用户(只有超级管理员才可以)
sudo adduser xxx家目录(主目录)
/home 专门用来存放除root用户的其他用户usermod :
修改用户名,修改用户的各种信息
sudo usermod -l lisi hqyj
sudo usermod -g hqyj xxx :把xxx放入hqyj这个组deluser:
删除用户
/etc/group :组的信息存储
如何看用户信息:放在 /etc/passwd /etc/shadow
进程状态:
S:sleep 堵塞状态
D:不可中断的堵塞
R: ready 正在执行中uid :谁在运行这个程序,
top:任务管理器,退出按q;
chmod(授权):改变权限的命令
sudo chemod a-x a.out 取消权限
sudo chemod a+x a.out 添加权限
sudo chemod u-x a.out ,user,group
sudo chemod 777 a.out 二进制
8.通配符
*:匹配任意长度的字符,它是匹配0和或者任意字符
?: 只匹配一个长度的字符
[...] : 匹配其中指定的字符
[ - ] : 匹配指定的字符范围
[^...] : 除了其中指定的字符,均可匹配
9.输入/输出重定向
> 在shell里面被称为输出重定向
即:把本应该输出到屏幕的内容输出到>号所指定的文件中< 在shell里面被称为输入重定向
即:把本应该从键盘获得的东西,从<号指定的文件中获得
10.管道
|:wc -l 统计输入的行数,
./编译后的程序 | ./编译后的程序
11.链接文件创建
-rw-rw-r-- 文件权限字符代表的有效位设为1,即“rw-”“rw-”和“r--”的八进制分别为110、110、100,则转换为八进制为6、6、4
第一组:代表文件的主人对该文件的权限
rw- :r:可读,w:可写,-:不可执行
第二组:代表文件的所属组的用户对该文件的权限
第三组:代表的是其他人对该文件的权限
1 :代表文件的硬链接数
in是用来创建链接文件的-硬链接文件:在windows里面没有对应的概念
cmp :比较
ln -s xxx xxx :创建软链接,软链接文件:它对应windows的快捷方式
12.如何修改源服务器
sudo cp /etc/apt/sources.list /etc/apt/sources.list.old
1、打开终端,先将sources.list文件备份一个,更新源服务器地址就是存在这个文件里面的,所以主要就是对这个文件进行编辑就可以了,也是很简单的。
输入:sudo cp /etc/apt/sources.list /etc/apt/sources.list.old2、打开sources.list文件,可以用你熟悉的任何文字编辑器vim,gedit,atom等都可以的。
输入:sudo gedit /etc/apt/sources.list3、把原来的,要替换的内容选中删除,然后把已经准备好的更新源地址复制进去就可以了。下面给出几个参考源地址。(提醒一下,注意自己的版本)
复制完后,保存退出。然后别忘了更新缓存。sudo apt-get update
13. 网络配置管理
1.配置IP地址等网络连通所必备的设置,一边让2台机器能够互相通信
2.在PC机上安装服务器软件,在开发板上安装客户端软件,以便让2台机器能够传送文件
IP地址:
如何查看机器的ip地址?
1、ifconfig :
IP地址是由4段数字组成,并且每段数字的范围是从0~254,
2、子网掩码(netmask):255.255.255.0
网络号:用于标识是哪一个局域网;
机器编号(主机号):用于标识是局域网中的那台机器
3、Ping:用来检测2台机器是否能相互通信,即两台机器是否连通
4、网关(gateway):一个网络通向其他网络的IP地址
5、DNS服务器:计算机域名系统,61.139.2.69
配置文件:放在/etc,.conf结尾就是配置文件
cd /etc -> cd netplan/ -> cat 01-network-manager-all.yaml -> sudo
14.NFS配置文件创建
1.mkdir testdir (创建文件夹)
2.进入新创建的文件里,并在里面下载nfs:sudo apt-get install nfs-kernel-server
3.输入:sudo service nfs-kernel-server status 查看当前NFS服务状态
4.停止:sudo service nfs-kernel-server stop
5.开始:sudo service nfs-kernel-server start
6.cd /etc -> sudo vim exports(进行修改配置)/source/rootfs *(rw,sync,no_root_squash)
7.重新启动NFS服务:sudo service nfs-kernel-server restart
8.查看NFS服务器的共享资源:showmount -e
9.查看当前NFS服务状态:sudo apt-get install nfs-kernel-server status
10.返回根目录:cd / 再进入到mnt文件中:cd /mnt
11.创建新的文件:sudo mkdir xi
12.在mnt文件中进行挂载共享资源:sudo mount -t nfs 192.168.249.128:/source/rootfs/ /mnt/xi/
13.将新创的文件进行可读写操作:sudo chmod 777 xi
14.ls 查看是否为共享文件资源,进入xi文件夹,进行创建文件,即可与另外窗口进行共享
另一个窗口操作:
1)进入根目录/下的/srv/tftp文件,查看是否存在
2)返回根目录/:sudo mkdir /source/rootfs -p 创建上述共享文件
3)进入source文件中,进行ls,即会显示rootfs共享文件
4)进入rootfs共享文件中进行创建.c文件以及文本,即可共享到另一个窗口(touch创建空文件)
二、 shell编程基础
1.建立shell脚本
vim test.sh -> #!/bin/bash
ls -l test.sh
2.赋予给文件权限
chmod a+x test.sh
3.执行shell脚本文件
./test.sh
1.shell变量
输出:echo $/echo $xxx
在shell中变量分为用户自定义变量,位置变量命令行参数,环境级变量,预定义变量。
用户自定义变量:写在用户的骨文件中,只针对当前用户生效;
位置变量命令行参数:由系统提供的参数;
环境级变量:只在当前 shell 中生效, 当shell关闭时变量便会丢失;
预定义变量:一开始时就定义的变量,通常是由$符和另一个符号组成。
1)用户自定义变量
shell允许用户建立变量存储数据,但它不支持数据类型(整型、字符、浮点型)。任何赋给变量的值都被shell解释为一串字符,变量命名规则同C++的命名规则,如下所示。
- 首个字符必须为字母(a~z,A~Z)或者下划线(_);
- 中间不能有空格,可以使用下划线(_);
- 不能使用其他标点符号。
#示例
#!/bin/bash
# 对变量赋值:
VAR="hello world" #等号两边均不能有空格存在
#打印变量VAR的值:
echo "VAR is:" $VAR
运行:
2)位置变量命令行参数
$0: 与键入的命令行一样,包含脚本文件名
![](https://i-blog.csdnimg.cn/blog_migrate/b0a30f7cb3e84223f113d2d04caac233.png)
3)环境级变量
环境变量也可叫全局变量,只在当前 shell 中生效, 当shell关闭时变量便会丢失;可以在创建他们的shell及派生出的子shell中使用(无需定义,直接可以使用,如:$UID)
相关命令:
set :输出所有变量
env:只显示全局变量
declare:输出所有变量,函数,整数等
##系统中无变量a,即输出空行
[root@localhost mnt]# echo $a
##查看当前系统所使用的shell
[root@localhost mnt]# echo $SHELL
/bin/bash
##查看当前系统用户的uid
[root@localhost mnt]# echo $UID
0
##查看当前系统用户家目录
[root@localhost mnt]# echo $HOME
/root
[root@localhost mnt]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
##查看系统中所有的shell
[root@localhost mnt]# cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
/bin/tcsh
/bin/csh
## /bin/sh 实质上就是 bash(软链接)
[root@localhost mnt]# ll /bin/sh
lrwxrwxrwx. 1 root root 4 Nov 17 22:30 /bin/sh -> bash
操作系统传递给程序的变量:PATH!!!:shell搜索路径
4)预定义变量
$0 ##获取脚本文件名,如果执行时包含路径,则输出脚本路径
$n(>0) ##以空格符为分隔符,脚本后的第n串字符 (n>0)
$# ##脚本后边跟的参数个数
$* ##脚本后所跟的所有参数
$@ ##脚本后所跟的所有参数(区别在于:$*表示脚本后边跟的是一串字符,而$@表示脚本后边跟的是多串字符)
$? ##获取上一条命令执行状态的返回值,非0为失败
$$ ##获取当前shell进程号
2.shell语句
①for语句
for Num in 1 5 7
do
echo $Num
sleep 1 ##休眠时间为1s,即间隔一秒再次执行
done
for Num in {1..10}
for Num in {10..1}
for Num in `seq 1 2 10` ##步长为2
例1:编写脚本 text.sh ,从userfile中取出要建立用户名建立用户
#!/bin/bash
[ -z "$1" ] && { ##检测是否为空
echo "please input userfile!!"
exit 1
}
[ ! -e "$1" ] && { ##检测是否存在
echo "ERROR : $1 is not exist"
exit 2
}
for NAME in `cat $1`
do
id $NAME &> /dev/null
[ "$?" -eq "0" ] && {
echo "$NAME is exist!!"
}||{
useradd $NAME &>/dev/null
echo "$NAME is created!"
}
done
②while语句 ----只判定一次
当条件为真
while true
do
done
update ##监测系统负载
echo$$ ##显示当前id
例:显示时间
#!/bin/bash
TTY=`ps $$| grep $$ |awk '{print $2}'`
while true
do
clear ##清屏
echo -ne `uptime` > /dev/$TTY
echo -ne '\r \r' ##不换行
sleep 1
done
三、C语言高级
C语言高级(在嵌入式开发当中,用的比较多的一些高级内容)结构体、共用体、数组、函数、指针
1.调试器gdb的使用
1.gcc加-g .c文件: gcc -g xxx.c -o xxx
2.启动gdb:输入gdb 跟上调试的名字 xxx
3.设置断点(程序在运行过程中会暂时停下来的位置) break xxx(main)
4.启动被调试程序:run
5.查看变量的值:print xxx
6.单步执行(让程序每次只执行一行):step :要进入子函数 ; next:不进入子函数
7.再查看变量的值
查看该错误行具体错误
8.结束调试:quit
命令都可缩写!!!
分号(;)空语句
2.指针
指针变量(简称指针)是一个变量,该变量存放的是某一个内存的地址
从逻辑上看,内存可以被视为一维字符数组,某一个内存的地址就是数组下标
P指向的位置:地址为x的位置1)指针的加减法运算
指针的加1操作,不是真的加1,而是加一个单位,一个单位多大,取决于指针变量的基类型
char *p:
P的类型是指针型,char代表P的基类型
指针减指针得到的是相差的单位数2)野指针:指向“垃圾”内存的指针,不是NULL指针
出现的原因:
- 指针变量没有初始化。
- 指针P被free之后,没有置为NULL。
C语言允许用数组的语法使用指针变量
int *p[3]:指针数组
int* p的元素的类型是int *型(指针型)
int(*p)[4]
P的基类型是int[4]
p指向的东西的类型是int[4]这种类型
p指向的东西的类型是数组型
int[4]是p的基类型
int[4]代表具有4个int型元素的一维数组int **q;
q是变量
q是指针变量
int * 是q的基类型
q指向的东西的类型是int* 型
q指向的的地方存放的内容的数据类型是int *型
3.函数的传参
采用的是值传递;
发生函数调用时,系统要将实参的值复制一份给形参
形参和实参虽然值一样,但却是两个不同的值
数组做函数的形参实际上是一个指针做函数的形参
函数2
#include <stdio.h>
void print_char(char c, int n, int m) //n行数 m 列数
{
int i, j;
for(i = 0; i < n; i++)
{
for(j = 0; j < m; j++)
{
printf("%c", c);
}
printf("\n");
}
}
int main()
{
char c;
int m, n;
scanf("%c%d%d", &c, &n, &m);
print_char(c, n, m);
}
函数3
#include <stdio.h>
void swap(int *a, int *b)
{
int t;
t = *a;
*a = *b;
*b = t;
}
void taxis(int *p, int n)
{
int i, j;
for(i = 0; i < n - 1; i++)
{
for(j = 0; j < n - i - 1; j++)
{
if(p[j] > p[j + 1])
{
swap(&p[j], &p[j + 1]);
}
}
}
}
int main()
{
int i, a[] = {90, 85, 76, 99, 62, 78};
taxis(a, 6);
for(i = 0; i < 6; i++)
printf("%d\n", a[i]);
}
函数5
#include <stdio.h>
int is_within(char *p, char ch);
int main(void)
{
char str[81];
char ch;
do
{
puts("input range string:");
gets(str);
puts("input match char:");
ch = getchar();
getchar();
if ( is_within(str, ch) ) puts("Find!");
else puts("Can't find!");
puts("input any char except q to go on.");
ch = getchar();
getchar();
}
while(ch != 'q');
puts("Quit.");
return 0;
}
int is_within(char *p, char ch)
{
while(*p != '\0')
{
if(*p == ch) return 1;
p++;
}
return 0;
}
函数7
#include <stdio.h>
float p(int x,int n)
{
float t,t1,t2;
if(n==0) return 1;
else if(n==1) return x;
else
{
t1=(2*n-1)*x*p(x,(n-1));
t2=(n-1)*p(x,(n-2));
t=(t1-t2)/n;
return t;
}
}
int main()
{
int x,n;
printf("input two int (x and n):");
scanf("%d%d",&x,&n);
printf("%.2f\n",p(x,n));
return 0;
}
4.递归函数(recusive)
自己调自己的函数
fac函数的功能:计算参数的阶乘
斐波那契数列
1 1 2 3 5 8 13 ......数学归纳法:
要证明在规模为n的情况下命题成立
1、先验证n=1的情况下,命题成立
2、假设在规模为n-1的情况下,命题成立,然后推导出在规模为n的命题成立
5.结构体
用于存放多个数据类型不一样的数据
int char short 简单数据类型只能存放一个数据
数组要求所有被存放的数据,类型都必须一样存学生信息:学号、姓名、成绩
1、定义结构体
2、定义个变量,变量的名字叫做yangzhu变量的数据类型是结构体数据类型
struct student{
int sno; //字段/成员
char sname[20];
float grade;
};
int main()
{
struct student yangzhu;
yangzhu.sno = 21;
yangzhu.grade = 62.5;
strcpy(yangzhu.sname,"yangzhu");
printf("%d\n",yangzhu.sno);
printf("%f\n",yangzhu.grade);
return 0;
}
typedef:用来定义数据类型的别名
typedef int YZ: 为数据类型int定义一个别名叫做YZ
typedef struct student{
int sno; //字段/成员
char sname[20];
float grade;
}STU;//typedef int YZ
int main()
{
STU yangzhu;
yangzhu.sno = 21;
yangzhu.grade = 62.5;
strcpy(yangzhu.sname,"yangzhu");
printf("%d\n",yangzhu.sno);
printf("%f\n",yangzhu.grade);
return 0;
}
结构体变量的初始化:
结构体数组:STU bianji[3] = {{1,"yangzhu",38},{2,"zhangsan",58},{3,"lisi",88}}; printf("%f\n",banji[1].grade); 结构体指针: STU yangzhu = {1,"yangzhu",38}; STU *p; // p就是结构体指针,通过p去访问yangzhu的成绩 p = &yangzhu; printf("%f\n",(*p).grade); //查看成绩 printf("%f\n",(*p)->grade); //->是C语言的一个运算符,自称为指向运算符
结构体的字段是按照定义时的顺序,依次连续存放的
要求结构体变量的内容在内存中存放的时候要对齐,和最长的简单类型对齐
6.共用体
共用体(联合体)
字段a和字段b共用同一个存储空间
特点:
所有字段都占有同一个存储空间,即,所有字段共享同一个存储空间。
union student{
int b;
char a
};
int main()
{
union stu yangzhu;
printf("%p\n",&yangzhu.a);
printf("%p\n",&yangzhu.b);
printf("%ld\n",sizeof(yangzhu); //4
return 0;
}
7.动态内存
程序编写的时候,不知道应该分配多少空间,一直要到程序运行起来之后,才能够准确的确定所需要的内存数
此时就不能在编写程序的时候分配内存空间,而要在程序运行期间动态内存空间
分配内存的时机是在程序运行起来后的某个时间点,而不是编写程序的时候就确定
8.库函数
malloc #includ <stdlib.h> malloc的返回值是分配出来的内存空间的首地址 free:释放空间 int num; int *p; printf("banji renshu"); scanf("%d",&num); p =(int *) malloc(num * sizeof(int)); if ( p == NULL) { printf("sorry,no memory\n"); exit(1); } while(1){ printf("tongxue chegnji"); for(int i = 0; i < num;i++) scanf("%d",p+i); for(int i = 0;i < num;i++) pritnf("%d\n",p[i]); } free(p); return 0;
void * :malloc的返回值的数据类型是指针型,现在不确定将来别人要用我分配出来的空间来存什么类型的数据,因
因此可通过外部给与权利
const:常量,变量对应的概念
1.定义常量时要进行初始化,常量不可改变
const *:
const int *p:p指向的地方是常量,不能通过P去修改P所指向的地方的值,该p是变量不是常量
int * const p:能通过P去修改P所指向的地方的值,但其指向不可以发生改变,p指向的位置不是常量
const int * const p:不能通过P去修改P所指向的地方的值,指向也不可以发生改变
9.gcc编译器
-g 生成调试符号表,以便用gdb进行调试
-0 :output定义编译输出的文件的名字 gcc test.c -o test(生成输出名字)
-O/O2 :进行优化
-I: gcc xx.c -o xx -I/home/xxxx
将后面的路径加入到头文件搜索路径
/usr/include : 系统头文件目录
/usr/lib 系统库文件目录-L: gcc -L 加进去的目录名
步骤:
1、预处理: gcc xxx.c -o xxx.i -E(进入源代码文件)
file GCC.i :查看文件
这项步骤的作用:去除注释、处理头文件、处理宏定义、处理条件编译2、编译:gcc xxx.c -o xxx.s -S
3、汇编:gcc xxx.c -o xxx.o -C
4、链接:把二进制代码链接到库的二进制代码
四、往期回顾
2. C语言基础练习题总结(嵌入式系列学习2)-CSDN博客
持续更新中.......
更多文章,点击左上角头像,查看个人简介和更多相关项目的分享,也可通过关注我的其他平台,一起学习,一起进步!Come on!!!动起手来,开始探索~~~