经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » Linux/Shell » 查看文章
Linux编程环境
来源:cnblogs  作者:AkiyamaYusuke  时间:2021/5/17 9:11:38  对本文有异议

Linux编程环境

【学习笔记】

vi编辑器

  1. vi 文件名 #进入文件编辑模式

一般模式:

  1. yy #复制当前行
  2. y数字y #复制多少行内容
  3. p #箭头移动到目的行粘贴
  4. u #撤销上一步
  5. dd #删除当前行
  6. d数字d #删除光标后多少行
  7. x #删除一个字母(相当于delete)
  8. X #删除一个字母(相当于backspace)
  9. yw #复制一个词
  10. dw #删除一个词
  11. shift+^ #移动到行头
  12. shift+^ #移动到行尾
  13. 1+shift+g #移动到页头
  14. shift+g #移动到页尾
  15. N+shift+g #移动到目标行

编辑模式:

  1. i #当前光标前
  2. a #当前光标后
  3. o #当前光标行的下一行
  4. delete #删除
  5. esc #退出编辑模式

指令模式:

  1. :w #保存
  2. :q #退出
  3. #强制执行
  4. :wq! #强制保存退出

gcc编译器

GCC 是一个交叉平台编译器,能够在当前CPU 平台上为多种不同体系结构的硬件平台开发软件,因此尤其适合在嵌入式领域的开发编译。

gcc编译支持文件

.c,C 语言源代码
.h,程序所包含的头文件
.i,已经预处理过的C 源代码文件
.s,汇编语言源代码文件
.o,编译后的目标文件

gcc编译流程

写个hello.c源代码

  1. gcc hello.c
  1. #include<stdio.h>
  2. int main()
  3. {
  4. printf(“Hello world!\n”);
  5. return 0;
  6. }

保存、退出

1、预处理

该阶段,编译器将上述代码中的stdio.h编译起来,可用“-E”选项查看

gcc格式为

  1. gcc [选项] 要编译的文件 [选项] [目标文件] #目标文件可缺省,默认生成.out文件
  1. gcc -E hello.c -o hello.i #-o:指目标文件;-i:指 已经预处理过的源程序

预编译阶段将“stdio.h”中的内容插入到hello.i文件中

2、编译

该阶段,gcc首先检查代码的规范性、语法错误;检查无误后,gcc把代码翻译成汇编语言。可用“-S”选项查看

  1. gcc -S hello.i -o hello.s

3、汇编

汇编阶段是把编译阶段生成的“.s”文件转成目标文件。读者在此可使用选项“-C”看到汇编代码已转化为“.o”的二进制目标代码。

  1. gcc c file.s o file.o

4、链接

在预编译中包含进的“stdio.h”中也只有该函数的声明,而没有定义函数的实现。那么,是在哪里实现“printf”函数的呢?答案是:系统把这些函数实现都做到名为libc.so.6 的库文件中去了。

在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,从而链接到libc.so.6 库函数,这样就能实现函数printf 了,这也就是链接的作用。

  1. gcc file.o o file

gcc编译选项

gcc [选项] [文件]

  1. -E:使用此选项表示仅作预处理,不进行编译、汇编和链接。
  2. -S:编译到汇编语言不进行汇编和链接。
  3. -c:编译到目标代码。
  4. -o:文件输出到文件。
  5. -static:此选项将禁止使用动态库,所以,编译出来的东西一般都很大,也不需要什么动态
  6. 链接库即可运行。
  7. -share:此选项将尽量使用动态库,所以生成文件比较小,但是需要系统有动态库。
  8. -I dir:在头文件的搜索路径列表中添加dir 目录。
  9. -L dir:在库文件的搜索路径列表中添加dir 目录。
  10. -llibrary:链接名为library 的库文件。

gdb调试器

Linux 的大部分特色源自于Shell 的GNU(GNU symbolic debugger)调试器,也称作gdb

gdb使用流程

启动gdb

以一段代码为例

  1. gcc gdb_sample.c
  1. #冒泡排序
  2. void bubble_sort(int arr[], int len) {
  3. int temp;
  4. for (int i = 0; i < len; i++) {
  5. for (int j = 0; j < len-1-i; j++) {//从第一个数开始,依次和后一个数比较
  6. if (arr[j] > arr[j + 1]) { #把较大的数交换到后边
  7. temp = arr[j];
  8. arr[j] = arr[j + 1];
  9. arr[j + 1] = temp;
  10. } #内层循环结束后,最大一个数排到最后,保持不动
  11. #每结束一次内层循环,比较次数少一次,因此有-i
  12. }
  13. }
  14. }
  15. int main(){
  16. int arr[] = { 22, 45, 67, 36, 93, 444, 26, 84, 3, 7 };
  17. int len = (int)sizeof(arr) / sizeof(arr[0]);
  18. bubble_sort(arr, len);
  19. for (int i = 0; i < len; i++) {
  20. printf("%d ", arr[i]);
  21. }
  22. }

退出保存后使用gcc对代码进行编译,注意一定要加上选项“-g”,这样编译出的可
执行代码中才包含调试信息,否则之后gdb 无法载入该可执行文件。

启动gdb进行调试:

  1. gcc -g gdb_sample.c -o gdb_sample

在gdb输入命令时,可用不用打全命令,在Linux下,可用敲击两次Tab键来补全命令。

调试命令

查看文件

输入l(list),查看所载入的文件(输入l即可,系统会自动识别)

设置断点
  1. break <function> #在进入指定函数时停住
  2. break <linenum> #在指定行号停住
  3. break +offsetbreak -offset #在当前行号的前面或后面的offset 行停住
  4. break filenamelinenum #在源文件filename 的linenum 行处停住
  5. break filenamefunction #在源文件filename 的function 函数的入口处停住
  6. break *address #在程序运行的内存地址处停住
  7. break #break 命令没有参数时,表示在下一条指令处停住
  8. breakif <condition> #…可以是上述的参数,condition 表示条件,在条件成立时停住
查看断点
  1. info breakpoints [n]
  2. info break [n]
运行代码

输入r(run)即可,gdb 默认从首行开始运行代码,若想从
程序中指定行开始运行,可在r 后面加上行号:

  1. r 10 #第十行开始执行
查看变量值
  1. p [变量]
恢复程序运行和单步运行
  1. step <count> #单步跟踪,如果有函数调用,它会进入该函数
  2. next <count> #同样单步跟踪,但如果有函数调用,不会进入该函数
  3. set step-modeset step-mode on #打开step-mode 模式
  4. set step-mod off #关闭step-mode 模式
  5. finish #运行程序,直到当前函数完成返回
  6. until u #当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体

Make工程管理

Makefile基本规则

一个简单的Makefile:结构组成

  1. all: #目标名字放在":"前面,名字由字母和下划线组成
  2. #":"后面是需要链接的文件
  3. echo "Hello World" #注意echo前必须有一个Tab键位,不能是空格
  4. #echo 后面是生成目标的命令
  5. test:
  6. echo "Test Target" #一个makefile可以定义多个目标

实例演示

vi max.h

  1. int max (int a, int b);

vi max.c

  1. int max(int a,int b){
  2. if(a>=b){
  3. return a;
  4. }
  5. else{
  6. return b;
  7. }
  8. }

vi min.h

  1. int min(int a,int b);

vi min.c

  1. int min(int a,int b){
  2. if(a<b){
  3. return a;
  4. }
  5. else{
  6. return b;
  7. }
  8. }

vi main.c

  1. #include <stdio.h>
  2. #include "max.h"
  3. #include "min.h"
  4. int main(int argc, char* argv[]){
  5. int a = 5;
  6. int b = 3;
  7. int maxNum= max(a,b);
  8. int minNum = min(a,b);
  9. printf("the max value is %d\nthe min value is %d\n",maxNum,minNum);
  10. return 0;
  11. }
一般编译流程

首先编译依赖库文件,然后编译main函数

编译依赖库

编译max.c

  1. gcc -c max.c -o max.o

编译min.c

  1. gcc -c min.c -o min.o
编译main函数

编译main.c

  1. gcc max.o min.o main.c -o main
执行main
  1. ./main
输出结果
  1. the max value is 5
  2. the min value is 3

如果依赖函数过多,或者调用o库文件多,这样编译将非常麻烦

于是采用makefile方式来进行简化

Makefile编译方式
创建Makefile文件
  1. vi Makefile #创建Makefile
  1. #编辑Makefile(模板)
  2. simple:main.o max.o min.o
  3. gcc -o simple main.o max.o min.o #Tab间隔
  4. main.o:main.c
  5. gcc -c main.c -o main.o
  6. max.o:max.c
  7. gcc -c max.c -o max.o
  8. min.o:min.c
  9. gcc -c min.c -o min.c
运行Makefile

方法一:在Makefile所在的目录下运行命令

  1. make

方法二:运行命令make all

  1. make [目标名]
输出
  1. gcc -c max.c -o max.o
  2. gcc -c min.c -o min.o
  3. gcc max.o min.o main.c -o simple
执行
  1. ./simple
输出
  1. the max value is 5
  2. the min value is 3

Makefile假目标

在前面的simple 项目中,现在假设在程序所在的目录下面有一个clean 文件,这个文件也可以用过touch命令来创建。

假目标可以采用.PHONY关键字来定义,需要注意的是其必须是大写字母

  1. .PHONY:clean #假目标
  2. simple:main.o max.o min.o
  3. gcc -o simple main.o max.o min.o #Tab间隔
  4. main.o:main.c
  5. gcc -c main.c -o main.o
  6. max.o:max.c
  7. gcc -c max.c -o max.o
  8. min.o:min.c
  9. gcc -c min.c -o min.c
  10. clean:
  11. rm main.o min.o max.o simple

采用.PHONY 关键字声明一个目标后,make 并不会将其当作一个文件来处理,而只是当作一个概念上的目标。对于假目标,我们可以想像的是由于并不与文件关联,所以每一次make 这个假目标时,其所在的规则中的命令都会被执行

Makefile变量

在Makefile 中通过使用变量来使得它更简洁、更具可维护性

自动变量

  1. $@ #表示一个规则中的目标。当我们的一个规则中有多个目标时,$@所指的是其中任何造成命令被运行的目标。(表示的是目标的集合)
  2. $^ #表示的是规则中的所有先择条件。(表示的是依赖的集合)
  3. $< #表示的是规则中的第一个先决条件。(表示目标列表里最后一个依赖)

【注意】由于在Makefile 中“$”具有特殊含义,因此,如果想采用echo 输出“$”,则必需用两个连着的“$”。还有就是,“$@”对于Shell 也有特殊的意思,我们需要

在“$$@”之前再加一个脱字符“\”。

其他一些字符的表示:

  1. %.o 表示所有的.o文件
  2. %.c 表示所有的.c文件
实例:
  1. .PHONY:clean
  2. CC = gcc #定义变量
  3. RM = rm
  4. OBJ = simple
  5. OBJS = main.o max.o min.o
  6. $(OBJ):$(OBJS)
  7. $(CC) -o $@ $^
  8. main.o:main.c
  9. $(CC) -c $^ -o $@
  10. max.o:max.c
  11. $(CC) -c $^ -o $@
  12. min.o:min.c
  13. $(CC) -c $^ -o $@
  14. clean:
  15. @$(RM) $(OBJS) $(OBJ)

Makefile函数

addprefix函数

addprefix 函数是用来给字符串中的每个子串前加上一个前缀,其形式是:$(addprefix prefix, names…)

  1. .PHONY:all
  2. SOURCE = main.c max.c min.c
  3. OBJS = /home/pyma/Makefile
  4. add source = $(addprefix $(OBJS)/. $(SOURCE))
  5. all:
  6. @echo $(add_source)

filter函数

filter 函数用于从一个字符串中,根据模式得到满足模式的字符串,其形式是:$(filter pattern..., text)

  1. .PHONY:all
  2. SOURCE = main.c max.c min.c
  3. OBJS = /home/pyma/Makefile
  4. add source = $(addprefix $(OBJS)/. $(SOURCE))
  5. sources = $(filter %.c %.s,$(add_source)
  6. all:
  7. @echo $(add_source)

从结果来看,经过filter 函数的调用以后,sources 变量中只存在.c 文件和.s 文件,而.h 文件则被过滤掉了

filter-out函数

filter-out 函数用于从一个字符串中根据模式滤除一部分字符串,其形式是:$(filter-out pattern..., text)

  1. .PHONY:all
  2. SOURCE = main.c max.c min.c
  3. OBJS = /home/pyma/Makefile
  4. add source = $(addprefix $(OBJS)/. $(SOURCE))
  5. sources = $(filter-out %.h,$(add_source)
  6. all:
  7. @echo $(add_source)

从结果来看,filter-out 函数将以“.h”为后缀的文件从add_source 变量中给滤除了。可以看出,filter 与filter-out 是互补的

wildcard函数

wildcard 是通配符函数,通过它可以得到我们所需的文件,这个函数相当于我们在Windows或是Linux 命令行中的“*”。其形式是:$(wildcard pattern)

  1. .PHONY:all
  2. SOURCE = $(wildcard *.c)
  3. OBJS = /home/pyma/Makefile
  4. add source = $(addprefix $(OBJS)/. $(SOURCE))
  5. all:
  6. @echo $(add_source)

运行结果:从当前Makefile 所在的目录下通过wildcard 函数得到所有的C 程序源文件

patsubst函数

patsubst 函数是用来进行字符串替换的,其形式是:$(patsubst pattern, replacement, text)

  1. .PHONY:clean
  2. CC = gcc #定义变量
  3. RM = rm
  4. OBJ = simple
  5. SRCS = $(wildcard *.c)
  6. OBJS = $(patsubst %.c,%.o,$(SRCS))
  7. $(OBJ):$(OBJS)
  8. $(CC) -O $@ $^
  9. main.o:main.c
  10. $(CC) -c $^ -o $@
  11. max.o:max.c
  12. $(CC) -c $^ -o $@
  13. min.o:min.c
  14. $(CC) -c $^ -o $@
  15. clean:
  16. @$(RM) $(OBJS) $(OBJ)

OBJS 变量中采用patsubst 函数进行字符串替换,将所有的.c 文件都替换成.o 文件。patsubst 函数可以使用模式,所以其也可以用于替换前缀等,功能更加强大

选自华清远见《嵌入式操作系统》

原文链接:http://www.cnblogs.com/AkiyamaYusuke/p/14756837.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号