Linux下vim编辑、makefile编译、GDB调试

Linux环境下C语言编程

1 .序

       笔者又来更新博客了,每次立下Flag说要一周一次更新博客,但总是拖,最后奈何4月份只更新了一次,说明四月份又浑浑噩噩度过了一个月,不过值得可喜的是笔者在4月份找了一份实习工作,在里面做嵌入式软件开发,目前负责QT的开发。

       笔者目前的Linux环境是ubantu16.04,gnome桌面环境,使用Linux系统时间久了不免产生审美疲劳,所以笔者就换了个MacOS的主题环境,果然界面焕然一新,又可以开开心心的编程了。附上桌面环境图。
在这里插入图片描述

2.Vim的相关操作

  在Linux下各种文件的配置信息,难免会用到编辑器,而Vim就是一款强大的编辑器,当然C语言的编程也需要Vim编辑器输入,有很多人觉得VIm的操作繁琐,不容易记住很多指令,不过笔者觉得只要记住常用几个指令就足以应付这些了。

(1)命令行模式,

  控制光标的移动、进行复制、粘贴、删除撤销等操作。通过 Ctrl+[ 可以返回到命令行模式。

  光标的移动通过上下左右 键来进行移动,当然也可以通过k j h l 来移动,使用字母键进行字符移动时,可以在其前面加数字,表示在对应的放下上进行移动。

  dd:表示删除一行,类似的ndd删除本行及下面的n行
  yy:复制一行,nyy复制当前行和下面的n行
  p:粘贴
  u:撤销
  gg/G:回到文首/文尾,然后输入数字,就可以跳转到行首,输入一个暴大的值,跳到行尾
  /或者?:后面输入数字,可以搜搜文本,n 或者shift+n 可以跳到下一个或者上一个
  0 或者$:行首(HOME) 行尾(END)也行

(2)插入模式,

  只有在插入模式下,才可以进行文字的输入,按字母 i 可以进入插入模式,就能正常的进行操作了,就类似于word的操作一样了,然后上文也说过了,通过 Ctrl + [ 可以退出插入模式,进入命令行模式。

(3)底行模式

  在退出插入模式后,按:可以进入底行模式,在底行模式下,可以进行文件的保存和退出。
   :q :不保存直接退出vim编辑器。
   :q! :不保存强制退出vim编辑器。
   :wq :保存退出vim编辑器。

3.C语言编程

   C语言的编程,必然需要编译链接成可执行文件。当然一般的C语言运行过程需要经过:预处理→编译→汇编→链接→可执行文件。在Linux环境下,可以使用gcc来编译链接生成可执行文件。

  1. 预处理
    下文中可以看到,经过预处理之后,编译器已经把需要包含的头文件编译到.i文件当中。-E
#include<stdio.h>
int main()
{
  int i,j;
  for(i=0,j=5;i<j;i++)
    printf("%d Hello World!",i);
  return 0; 
}
gcc test.c -o test.i -E
extern int pclose (FILE *__stream);
extern char *ctermid (char *__s) __attribute__ ((__nothrow__ , __leaf__));
#912 "/usr/include/stdio.h" 3 4
extern void flockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
extern int ftrylockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__)) ;
extern void funlockfile (FILE *__stream) __attribute__ ((__nothrow__ , __leaf__));
#942 "/usr/include/stdio.h" 3 4
#2 "test.c" 2
#2 "test.c"
int main()
{
  int i,j;
  for(i=0,j=5;i<j;i++)
    printf("%d Hello World!",i);
  return 0;
}
  1. 编译
    编译阶段,就是编译器把源代码编译成.s汇编程序,可以试着点开.s文件查看一下。-s
gcc test.i -o test.s -S
.LC0:
        .string "%d Hello World!"
        .text
        .globl  main
        .type   main, @function
main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movl    $0, -8(%rbp)
        movl    $5, -4(%rbp)
        jmp     .L2
  1. 汇编
    将汇编语言源程序汇编成目标文件。-c
gcc test.s -o test.o -c
  1. 链接
    将目标程序链接相应的库函数生成可执行文件,之后执行,可以看到成功正确执行函数功能。
gcc test.o -o test
./test
0 Hello World!1 Hello World!2 Hello World!3 Hello World!4 Hello World!

*****不过正常直接一步就可以生成可执行文件来运行。

gcc test.c -o test
./test 
0 Hello World!1 Hello World!2 Hello World!3 Hello World!4 Hello World!

makefile文件的使用

   当然这只是单文件的C语言运行,如果涉及到多个文件的编译的时候,就需要注意到编译顺序了,被调用的文件需要先编译产生.o文件,然后再配合调用函数的.o文件一起生成可执行文件。接下来举个栗子。

  主函数test.c文件,主要包含子文件:print.c、hello.c、和Add.c文件,都在主函数中调用。

#include<stdio.h>
#include"print.h"
#include"hello.h"
#include"Add.h"
int main()
{
 int a,b;
  hello();
  printf("请输入两个计算的数\n");
  scanf("%d\n %d",&a,&b);
  int c=Add(a,b);
  print(c);
  printf("\n结束!");
  printf("终于学会make编译了!\n");
  return 0;
}

hello.c和hello.h文件:也主要是打印,负责刚开始的内容输出。

#include"hello.h"
void hello()
{
  printf("hello,world,今天开始学习make编译!\n");
}

//接下来是hello.h文件 ,只是负责对使用的函数进行声明。
#include<stdio.h>
void hello();

print.c和printf.h文件:主要负责打印,当然直接就可以使用printf,我这里是为了说明生成可执行文件的编译顺序。

#include<stdio.h>
#include"print.h"
void print(int c)
{
   printf("c=%d ",c);
}

//接下来是print.h文件 ,只是负责对使用的函数进行声明。
#include"stdio.h"
void print(int c);

Add.c和Add.h文件:主要是对输入的两个数进行相加,返回输出结果,也是在主函数中调用。

#include<stdio.h>
#include"Add.h"
int Add(int a,int b)
{
   int c=a+b;
   return c;
}
//接下来是Add.h文件 ,只是负责对使用的函数进行声明。
#include"stdio.h"
int Add(int a,int b);

   由于在主函数中先调用的hello.c文件,所以你就先编译hello.c生成.o文件,当然你如果先编译Add.c或者print.c也是可以的,因为他们三个没有互相调用,当如果hello.c调用print.c中的函数,这个时候你就需要先编译print.c文件,然后才能编译hello.c文件。

   之后再将生成的目标文件链接相应的库生成可执行文件。接下来,就按照讲的顺序来编译运行链接运行一下程序。

gcc hello.c -o hello.o -c
gcc Add.c -o Add.o -c
gcc print.c -o print.o -c
gcc test.c -o test.o -c

gcc test.o print.o hello.o Add.o -o test

./test

hello,world,今天开始学习make编译!
请输入两个计算的数
12
34 
c=46 
结束!终于学会make编译了!

   是不是有一点小开心,自己今天终于有收获了,进步就是这样一点点来的。
   当然如果每次修改一下程序都要这样编译一下,是不是会觉得很浪费时间,当然这还是只有几个文件,如果出现上百个文件,岂不是时间都花在编译指令上了,调试起来太麻烦了,所以就出现了makefile文件。

   makefile文件中主要放的就是你程序的编译指令,通过make就可以直接执行makefile文件中的指令,就进行编译了,无需再慢慢每个文件进行编译了。

   接下来就看看makefile文件的编写规则。首先放一个我自己写的刚刚的那个工程的makefile文件。

test:test.o Add.o hello.o print.o 
	gcc -o test test.o Add.o hello.o print.o 
test.o: test.c Add.h hello.h print.h
	gcc -c test.c -o test.o
Add.o: Add.c Add.h
	gcc -c Add.c -o Add.o
hello.o: hello.c hello.h
	gcc -c hello.c -o hello.o
print.o: print.c print.h
	gcc -c print.c -o print.o
clean:
	rm *.o test

   顶层需要写自己最后生成的目标文件,也就是可执行文件test,:感叹号后面的就是生成可执行文件需要用到的目标文件,

  下面就是生成可执行文件的指令,需要把所有的目标文件链接形成可执行文件。

  接下来就是目标文件的生成,需要用到-c这个指令,把每个.c文件都生成.o文件就可以了。

  最后一行的话,是清除生成的.o文件。接下来我们用makefile指令编译一下,make之后,就可以看到编译器有相应的输出,之后可以看到有可执行文件test了。

make
#编译器输出
gcc -c test.c -o test.o
gcc -c Add.c -o Add.o
gcc -c hello.c -o hello.o
gcc -c print.c -o print.o
gcc -o test test.o Add.o hello.o print.o

./test

hello,world,今天开始学习make编译!
请输入两个计算的数
12 34
c=46 
结束!终于学会make编译了!

   其中比较关键的两点需要注意的就是:
第一点是默认的makefile文件名有两种:makefile或者Makefile,

   这两种可以直接使用make指令,编译器是可以识别的,如果换成其他的文件,就需要用到-f指令了,例如

make
#编译器输出
make: *** 没有指明目标并且找不到 makefile。 停止。

make -f MakeFile
#编译器输出
make: 'test' is up to date.

第二点是makefile文件在书写编译指令的时候(第二行中gcc那一行),需要使用Tab键来空格,要不然会出现错误。

GDB调试

   习惯了Windows上面软件自带调试系统,可以随意设置断点、单步、运行等调试手段,Linux上面的调试方式还真有点不习惯 ,有点原生态,什么都需要自己去写,去设置,比如上面的编译。

  1. 首先想用gdb调试,在写makefile文件时,要加入 -g调试选项。
    在这里插入图片描述
  2. 然后gdb+可执行文件,即可进入调试界面。
    在这里插入图片描述
    在这里插入图片描述
  3. b + 行数,然后r 即可运行到指定的程序行数
    在这里插入图片描述
  4. print + 变量,即可查看变量的内容
    在这里插入图片描述
  5. n可以单步调试,但是不进入程序内部
    在这里插入图片描述
  6. s单步调试,但进入程序内部
    在这里插入图片描述
  7. 如果不设断点,可以直接r运行程序。
    在这里插入图片描述

   基本上面这些就满足日常的调试需求。
   gdb+运行程序的好处就是,如果遇到段错误(segmentation fault),可以直接停在错误的地方,可以看到错误的行数以及在哪个文件,方便查找错误,

  如果直接运行程序,程序退出后,只是显示段错误,并不会提示其他信息。当然如果语法错误,编译的时候就会显示出来。

如有雷同,纯属我抄你,有问题可以直接联系邮箱,在个人资料里面。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张一西

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值