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:撤銷

(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),可以直接停在錯誤的地方,可以看到錯誤的行數以及在哪個文件,方便查找錯誤,

  如果直接運行程序,程序退出後,只是顯示段錯誤,並不會提示其他信息。當然如果語法錯誤,編譯的時候就會顯示出來。

如有雷同,純屬我抄你,有問題可以直接聯繫郵箱,在個人資料裏面。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章