首页 > 系统相关 >Linux命令基础——makefile+gdb+IO

Linux命令基础——makefile+gdb+IO

时间:2022-11-08 20:04:53浏览次数:40  
标签:文件 gcc main int makefile gdb fd IO include

在学习Linux命令基础总结了笔记,并分享出来。

08-linux-day03(makefile-gdb-IO)

目录:附:ftp工具介绍——FlashFXP一、学习目标二、makefile1、makefile编写12、makefile编写23、makefile编写34、makefile补充三、gdb1、gdb调试2、gdb调试core文件四、系统函数1、系统api与库函数的关系2、open、close函数介绍3、open、close实现4、read、write5、lseek实现文件读写位置改变6、lseek计算文件大小7、lseek拓展文件8、阻塞和非阻塞相关的概念9、fcntl函数设置非阻塞


附:ftp工具介绍——FlashFXP

FlashFXP允许你从任何FTP服务器直接传输文件到你的本地硬盘,或者在两个FTP站点之间传输文件,即站点到站点传输,而无须经过自己的计算机。要实现站点至站点的文件传递,我们需要将本地文件浏览器界面切换至远程文件浏览器界面,并且需要两个站点都支持此功能。

ubuntu安装ftp服务器(一般配置)+FlashFXP与虚拟机传输文件——javascript:void(0)

使用:打开“站点”——>“站点管理器”——>“新建站点”,名字随便起(如:new),确定——>连接类型:选择“SFTP over SSH”;地址输入:“192.168.5.100”(Ubuntu的IP地址),用户名输入:wang,密码输入:root;远程路径输入:/home/wang(也可以不配置)——>点击“应用”;点击“连接”。

连接成功后,左侧为“Windows系统的文件”,右侧为“Ubuntu的文件”,将左右侧分别选择到文件位置和待拷贝的位置,然后鼠标选中“准备拷贝的文件”,然后鼠标右键“传输选定项”,就会传到“待拷贝位置”。


一、学习目标

1、熟练使用规则编写简单的makefile文件

2、熟练使用makefile中的变量

3、熟练使用makefie中的函数

4、熟练掌握gdb相关调试命令的使用

5、了解概念:pcb和文件描述符,虚拟地址空间

6、熟练掌握Linux系统IO函数的使用(open、read、write、lseek)

7、了解阻塞和非阻塞的概念

二、makefile

文件准备:head.h main.c add.c sub.c div.c mul.c

新建目录include,将head.h放入其中,head.h:



1 int add(int a, int b);
2 int sub(int a, int b);
3 int div(int a, int b);
4 int mul(int a, int b);



main.c:



1 #include <stdio.h>
2 #include "head.h"
3 int main(int a, int b)
4 {
5 int sum = add(2, 24);
6 printf("sum = %d\n", sum);
7 return 0;
8 }



add.c:



1 #include "head.h"
2 int add(int a, int b)
3 {
4 int result = a + b;
5 return result;
6 }



sub.c:



1 #include "head.h"
2 int sub(int a, int b)
3 {
4 int result = a - b;
5 return result;
6 }



div.c:



1 #include "head.h"
2 int div(int a, int b)
3 {
4 int result = a / b;
5 return result;
6 }



mul.c:



1 #include "head.h"
2 int mul(int a, int b)
3 {
4 int result = a * b;
5 return result;
6 }



1、makefile编写1

(1)makefile的命名规则:

  makefile

  Makefile

(2) makefile的三要素

  目标

  依赖

  规则命令

(3)写法

目标:依赖

Tab键 规则命令

如:(第1版makefile)

app:main.c add.c sub.c div.c mul.c

  gcc -o app -I./include main.c add.c sub.c div.c mul.c

如果更改其中一个文件,所有的源码都重新编译

可以考虑编译过程分解,先生成.o文件,然后使用.o文件生成结果(规则是递推的,依赖文件如果比目标文件新,则重新生成目标)

如:(第二版makefile)

app:main.o add.o sub.o div.o mul.o

  gcc -o app -I./include main.o add.o sub.o div.o mul.o

main.o:main.c

  gcc -c main.c -I ./include

add.o:add.c

  gcc -c add.c -I ./include

sub.o:sub.c

  gcc -c sub.c -I ./include

div.o:div.c

  gcc -c div.c -I ./include

mul.o:mul.c

  gcc -c mul.c -I ./include

更改:

#ObjFiles定义目标文件

ObjFiles=main.o add.o sub.o div.o mul.o

#目标文件用法:$(var)

app:$(ObjFiles)

  gcc -o app -I./include main.o add.o sub.o div.o mul.o

main.o:main.c

  gcc -c main.c -I ./include

add.o:add.c

  gcc -c add.c -I ./include

sub.o:sub.c

  gcc -c sub.c -I ./include

div.o:div.c

  gcc -c div.c -I ./include

mul.o:mul.c

  gcc -c mul.c -I ./include

2、makefile编写2

makefile的隐含规则:默认处理第一个目标

》函数:

  wildcard可以进行文件匹配

  patsubst内容的替换

》变量:

  $@——代表目标

  $^——代表全部依赖

  $<——第一个依赖

  $?——第一个变化的依赖

继续更改:(第三版makefile)

#get all .c files

SrcFiles=$(wildcard *.c)

#all .c files --> .o files

ObjFiles=$(patsubst %.c,%.o,$(SrcFiles))

#目标文件用法:$(var)

app:$(ObjFiles)

  gcc -o app -I./include $(ObjFiles)

#模式匹配规则,$@,$<,这样的变量,只能在规则中出现

%.o:%.c

  gcc -c $< -I./include -o $@

#测试变量

test:

  echo $(SrcFiles)

  echo $(ObjFiles)

》测试变量:make test

3、makefile编写3

》增加清理功能,

继续更改:(第四版makefile)

#get all .c files

SrcFiles=$(wildcard *.c)

#all .c files --> .o files

ObjFiles=$(patsubst %.c,%.o,$(SrcFiles))

#目标文件用法:$(var)

app:$(ObjFiles)

  gcc -o app -I./include $(ObjFiles)

#模式匹配规则,$@,$<,这样的变量,只能在规则中出现

%.o:%.c

  gcc -c $< -I./include -o $@

#测试变量:@命令不输出

test:

  @echo $(SrcFiles)

  @echo $(ObjFiles)

#清理功能:-f强制删除;规则前的@命令代表不输出该条规则的命令;规则前的-代表该条规则执行报错,继续执行;

clean:

  -@rm *.o

  rm -f app

》清理文件:make clean

》在本目录下增加clean文件,clean不能使用

继续更改:(第五版makefile)

#get all .c files

SrcFiles=$(wildcard *.c)

#all .c files --> .o files

ObjFiles=$(patsubst %.c,%.o,$(SrcFiles))

all:app app1

(空行)

#目标文件用法:$(var)

app:$(ObjFiles)

  gcc -o $@ -I./include $(ObjFiles)

app1:$(ObjFiles)

  gcc -o $@ -I./include $(ObjFiles)

#模式匹配规则,$@,$<,这样的变量,只能在规则中出现

%.o:%.c

  gcc -c $< -I./include -o $@

#测试变量:@命令不输出

test:

  @echo $(SrcFiles)

  @echo $(ObjFiles)

#清理功能:-f强制删除;规则前的@命令代表不输出该条规则的命令;规则前的-代表该条规则执行报错,继续执行;

#定义伪目标,防止有歧义

.PHONY:clean all

clean:

  -@rm -f *.o

  -@rm -f app app1

》清理文件:make clean

4、makefile补充

(1)头文件更改,.o需要重新编译,所以不推荐把头文件放到app:$(ObjFiles) include/head.h

(2)指定编译某个文件:make -f makefile1

三、gdb

文件准备:head.h fun.c main.c(在目录gdb0629下)



main.c:
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include "head.h"
5 typedef struct TTfunInfo
6 {
7 int fun_type;//函数的类型
8 int a;//函数的第一个参数
9 int b;//函数的第二个参数
10 char funname[10];//函数名称
11 }TfunInfo;
12 int main(int argc, char* argv[])
13 {
14 int a = 2;
15 int i = 0;
16 int a1 = 10, b1 =5;
17 TfunInfo funinfo[2];
18 char *Msg = "I will die!";
19 //Msg[0] = '1';
20 if(argc == 3)
21 {
22 a1 = atoi(argv[1]);
23 b1 = atoi(argv[2]);
24 funinfo[0].a = a1;
25 funinfo[0].b = b1;
26 funinfo[1].a = a1;
27 funinfo[1].b = b1;
28 }
29 for(i = 0; i < 2; i++)
30 {
31 printf("i===%d,LINE=%d\n",i,__LINE__);
32 if(i == 0)
33 {
34 funinfo[i].fun_type = 1;//call sum
35 printf("begin call sum\n");
36 strcpy(funinfo[i].funname, "sum");
37 sum(funinfo[i].a, funinfo[i].b);
38 }
39 if(i == 1)
40 {
41 funinfo[i].fun_type = 2;//call mul
42 printf("begin call mul\n");
43 strcpy(funinfo[i].funname, "mul");
44 mul(funinfo[i].a, funinfo[i].b);
45 }
46 }
47 printf("byebye\n");
48 return 0;
49 }



head.h:



1 int sum(int a, int b);
2 int mul(int a, int b);



func.c:



1 #include <stdio.h>
2 #include "head.h"
3
4 int sum(int a, int b)
5 {
6 printf("weldome call %s,a=%d,b=%d\n",__FUNCTION__,a,b);
7 return a+b;
8 }
9 int mul(int a, int b)
10 {
11 printf("weldome call %s,a=%d,b=%d\n",__FUNCTION__,a,b);
12 return a*b;
13 }



1、gdb调试

使用gdb:编译的时候加-g参数

  如:gcc func.c main.c -o app -I./ -g

启动gdb:gdb app(对应可执行程序名)

  按回车可以继续执行下一条指令

  r(un)——启动

    run也可以指定参数,如:r 12 7(相当于./app 12 7)

  start——启动,停留在main函数,分步调试

  n(ext)——下一条指令,

  s(tep)——下一条指令,可以进入函数内部,库函数不能进

  q(uit)——退出gdb

  set——给参数或变量赋值

    设置启动参数:set args 10 6(相当于./app 10 6)

    set 变量名=值(如:set args=3——当函数执行至断点前,临时把判断条件的值改变)

          (如:set argv[1]="12";(回车)set argv[2]="7"——临时把argv[1]和argv[2]赋值)

  l(ist)——默认查看还有main函数的代码,默认10行,回车,继续10行

    l 文件名:行号(如:l func.c:1——查看func.c从第1行开始的10行代码)

  b(reak)——增加断点

    b 行号(如:b 17——默认在main函数第17行设置了断点)

    b 函数名(如:b sum——在func.c的sum函数处设置了断点)

    b 文件名:行号(如:b func.c:6——func.c第6行设置了断点)

    设置条件断点

      b 行号 条件(如:b 32 if i==1——只有if=1的时候才进入断点,即停止)

  i(nfo) b——查看所有断点编号

  d(elete)——删除断点

    d 断点标号(如:d 4——删除info表中的4号断点)  

  c(ontinue)——继续执行,直到下一个断点

  p(rint)——打印变量的值

    p 变量名(如:p argc——打印变量argc的值:$1 = 3)

    p 结构体名(如:p funinfo——打印结构体funinfo中各个值的信息:$2 = {{fun_type = 1, a = 10, b = 419666005, funname = }...})

    p 变量名(如:p i——打印i的值:$3 = 0)

  ptype——打印 变量的类型

    ptype 变量(如:ptype i——打印i的类型:type = int)

   display——追踪某个变量的值,查看变量具体什么时候变化,每步执行,都打印

    display 变量名(如:display argc——跟踪输出argc的值:argc = 1)

    info display——查看所有跟踪的变量名及编号

  undisplay——删除显示变量,需要查看编号

    undisplay 编号(如:undisplay 1——删除跟踪编号为1的变量)

2、gdb调试core文件

     设置生成core:ulimit -c unlimited

  取消生成core:ulimit -c 0

  设置core文件格式:/proc/sys/kernel/core_pattern

    文件不能vi,可以用后面的套路 echo "/corefile/core-%e-%p-%t">/proc/sys/kernel/core_pattern

      %e:添加命令名;%p添加pid;%t添加core文件生成时的unix时间

core记录了案发现场

  gdb app core——将会显示在哪里出错了,如果还是看不到,输入where查看

四、系统函数

1、系统api与库函数的关系



Linux命令基础——makefile+gdb+IO_ubuntu





Linux命令基础——makefile+gdb+IO_python_02



2、open、close函数介绍

》open

  查看man 2 open

    int open(const char* pathname, int flags);

    int open(const char* pathname, int flags, mode_t mode);

      pathname 文件名

      flags

        必选项:

          O_RDONLY只读;

          O_WRONLY只写;

          O_RDWR读写

        可选项:

          O_APPEND追加;

          O_CREAT创建文件

            O_EXCL与O_CREAT一起使用,如果文件存在,则报错

            mode权限位,最终(mode &~ umask)

          ONONBLOCK非阻塞

      返回值:返回最小的可用文件描述符,失败返回-1,设置errno

》close

  查看:man 2 close  

    int close(int fd);

      fd open打开的文件描述符

      返回值:成功返回0,失败返回-1,设置errno

3、open、close实现



Linux命令基础——makefile+gdb+IO_java_03



练习:mytouch.c(open与close实现touch的弱化功能)

>touch mytouch.c

>vi mytouch.c



1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<fcntl.h>
5 #include<unistd.h>
6
7 int main(int argc,char* argv[])
8 {
9 if(argc != 2)
10 {
11 printf("./a.out filename\n");
12 return -1;
13 }
14 int fd = open(argv[1], O_RDONLY | O_CREAT, 0666);
15 close(fd);
16 return 0;
17 }



>gcc mytouch.c

>./a.out

>./a.out xxx

4、read、write

》read

  查看:man 2 read

    ssize_t read(int fd,void *buf,size_t count);

      fd:文件描述符

      buf:缓冲区

      count:缓冲区大小

      返回值:失败返回-1,设置errno;成功返回读到的字节数,0代表读到文件末尾

      非阻塞的情况下read返回值为-1,但是此时需要判断errno的值

》write

  查看:man 2 write

    ssize_t write(int fd, const void* buf, size_t count);

      fd:文件描述符

      buf:缓冲区

      count:缓冲区大小

      返回值:失败返回-1,设置errno;成功返回写入的字节数,0代表未写入

需求:实现一个cat功能,读文件,输出到屏幕

>touch mycat.c

>vi mycat.c



1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<fcntl.h>
5 #include<unistd.h>
6
7 int main(int argc,char* argv[])
8 {
9 if(argc != 2)
10 {
11 printf("./a.out filename\n");
12 return -1;
13 }
14 int fd = open(argv[1], O_RDONLY);
15
16 //读,输出到屏幕
17 char buf[256];
18 int ret = read(fd,buf,sizeof(buf));
19 //循环读取,读到0,结束
20 while(ret != 0)
21 {
22 write(STDOUT_FILENO, buf, ret);
23 ret = read(fd,buf,sizeof(buf));
24 }
25 write(STDOUT_FILENO, buf, ret);
26
27 close(fd);
28 return 0;
29 }



>gcc mycat.c

>./a.out mycat.c

5、lseek实现文件读写位置改变

lseek作用:

》lseek移动文件读写位置

》lseek计算文件大小

》拓展文件

需求:打开一个文件,写入内容:helloworld,然后读取一下文件内容,输出到屏幕。

》lseek移动文件读写位置

  man 2 lseek

    off_t lseek(int fd, off_t offset, int whence);

      fd 文件描述符

      offset 偏移量

      whence

        SEEK_SET 文件开始位置

        SEEK_CUR 当前位置

        SEEK_END 结尾

      返回值:成功返回当前位置到开始的长度,失败返回-1,设置errno

代码如下:(lseek解决了写入文件后文件指针已经在文件末尾,读取读不到的问题)

>touch myreadwrite.c

>vi myreadwrite.c



1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<fcntl.h>
5 #include<unistd.h>
6
7 int main(int argc,char* argv[])
8 {
9 if(argc != 2)
10 {
11 printf("./a.out filename\n");
12 return -1;
13 }
14 int fd = open(argv[1], O_RDONLY|O_CREAT,0666);
15
16 write(fd, "helloworld", 11);
17
18 //文件读写位置此时到末尾,需要移动读写位置
19 lseek(fd,0,SEEK_SET);
20 char buf[256] = {0};
21 int ret = read(fd, buf, sizeof(buf));
22
23 if(ret)
24 {
25 write(STDOUT_FILENO, buf, ret);
26
27 }
28
29
30 close(fd);
31 return 0;
32 }



>gcc myreadwrite.c

>./a.out 111

6、lseek计算文件大小

》lseek计算文件大小

>touch filesize.c

>vi filesize.c



1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<fcntl.h>
5 #include<unistd.h>
6
7 int main(int argc, char* argv[])
8 {
9 if(argc != 2)
10 {
11 printf("./a.out filename\n");
12 return -1;
13 }
14
15 //1.open
16 int fd = open(argv[1],O_RDONLY);
17 //2.lseek,得到返回值
18 int ret = lseek(fd, 0, SEEK_END);
19 printf("file size is %d\n", ret);
20 //3.close
21 close(fd);
22 return 0;
23 }



>gcc filesize.c

>./a.out mycat.c

7、lseek拓展文件

》拓展文件

>touch filecreate.c

>vi filecreate.c



1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<fcntl.h>
5 #include<unistd.h>
6
7 int main(int argc, char* argv[])
8 {
9 if(argc != 2)
10 {
11 printf("./a.out filename\n");
12 return -1;
13 }
14
15 //1.open
16 int fd = open(argv[1],O_WRONLY|O_CREAT,0666);
17 //2.lseek,拓展文件
18 int ret = lseek(fd, 1024, SEEK_END);
19 //需要至少写一次,否则不能保存
20 write(fd, "a", 1);
21 //3.close
22 close(fd);
23 return 0;
24 }



>gcc filecreate.c

>./a.out xxx.avi

>vi xxx.avi

8、阻塞和非阻塞相关的概念

》阻塞的概念:

  read函数在读设备或者读管道,或者读网络的时候

   输入输出设备对应/dev/tty

>touch read_tty.c

>vi read_tty.c



1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<fcntl.h>
5 #include<unistd.h>
6 #include<string.h>
7
8 int main(int argc, char* argv[])
9 {
10 int fd = open("/dev/tty",O_RDWR|O_NONBLOCK);
11
12 char buf[256];
13 int ret = 0;
14 while(1)
15 {
16 ret = read(fd, buf, sizeof(buf));
17 if(ret < 0) //如果没有输入,会报错
18 {
19 perror("read err:");
20 printf("ret is %d\n", ret);
21 }
22 if(ret) //输入,阻塞
23 {
24 printf("buf is %s\n", buf);
25 }
26 printf("haha\n");
27 sleep(1);
28 }
29 close(fd);
30 return 0;
31
32 }



>gcc read_tty.c

>./a.out

>xxx

9、fcntl函数设置非阻塞

》fcntl函数

  man 2 fcntl

    int fcntl(int fd, int cmd, .../* arg */);

>touch read_tty.c

>vi read_tty.c



1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<fcntl.h>
5 #include<unistd.h>
6 #include<string.h>
7
8 int main(int argc, char* argv[])
9 {
10 int fd = open("/dev/tty",O_RDWR);
11
12 //fcntl()函数,设置非阻塞
13 int flags = fcntl(fd, F_GETFL);
14 flags |= O_NONBLOCK;
15 fcntl(fd, F_SETFL, flags);
16
17 char buf[256];
18 int ret = 0;
19 while(1)
20 {
21 ret = read(fd, buf, sizeof(buf));
22 if(ret < 0) //如果没有输入,会报错
23 {
24 perror("read err:");//perror函数可以把read函数的错误信息打印出来
25 printf("ret is %d\n", ret);
26 }
27 if(ret) //输入,阻塞
28 {
29 printf("buf is %s\n", buf);
30 }
31 printf("haha\n");
32 sleep(1);
33 }
34 close(fd);
35 return 0;
36
37 }



>gcc read_tty.c

>./a.out

>xxx

在学习Linux命令基础总结了笔记,并分享出来。

标签:文件,gcc,main,int,makefile,gdb,fd,IO,include
From: https://blog.51cto.com/u_15405812/5834772

相关文章