1. 程式人生 > >Linux開發入門筆記——C程式設計

Linux開發入門筆記——C程式設計

Linux下的程式設計主要指C程式設計,它與其他環境中的C程式設計一樣,主要涉及到編輯器、編譯連結器、偵錯程式及專案管理工具。

GNU CC程式設計

GCC編譯器能將C、C++語言源程式、彙編程式和目標程式編譯、連線成可執行檔案,如果沒有給出可執行檔案的名字,GCC將生成一個名為a.out的檔案。 在Linux系統中,編譯器通過程式的副檔名可分辨出編寫原始程式程式碼所用的語言,由於不同程式所需要執行編譯的步驟是不同的。因此GCC可根據不同的副檔名對它們進行分別處理。

GCC所支援的副檔名檔案 在這裡插入圖片描述

GCC 編譯過程

編譯過程分為四個階段 預處理(Pre-Processing) 編譯(Compiling) 彙編

(Assembling) 連結(Linking)

基本語法格式 gcc [選項] 原始檔 [選項] [目標檔案]

舉例

$gcc -E hello.c -o hello.i
#“-E”  指定只進行預處理
#“hello.c”是源程式檔案
#“-o”指定生成目標檔案
#“hello.i”是預處理過程生成的目標檔案

$gcc -S hello.i -o hello.S
#“-S”指定只進行到編譯階段
#“hello.i”是進行編譯的原始檔
#“-o”指定生成目標檔案
#“hello.S”是編譯生成的目標檔名

$gcc -c hello.S -o hello.o
#“-c”指定只進行到彙編階段結束為止
#“hello.S”是進行彙編的原始檔 #“-o”指定生成目標檔案 #“hello.o”是編譯生成的目標檔名。hello.o為二進位制目的碼檔案 $gcc hello.o -o hello #該命令gcc之後無選項引數,表示對指定的原始檔進行編譯,直到輸出執行檔案(示例中的原始檔為hello.o,輸出的執行檔案hello)。 $./hello #執行該可執行檔案

在這裡插入圖片描述

函式庫建立和使用

函式庫一般分為靜態庫動態庫兩種。

靜態庫是指編譯連結時,把庫檔案的程式碼全部加入到可執行檔案中,因此生成的檔案比較大,但在執行時也就不再需要庫檔案了。其後綴名一般為“.a”

動態庫與之相反,在編譯連結時並沒有把庫檔案的程式碼加入到可執行檔案中,而是在程式執行時執行連結檔案載入庫,這樣可以節省系統的開銷。動態庫一般字尾名為“.so”

,如前面所述的libc.so.6就是動態庫。GCC在編譯時預設使用動態庫。

  • 靜態庫建立步驟一 編輯原始檔libhello.h
#ifndef _libhello_H_
#define _libhello_H_
void print_hello(void);
#endif

編輯原始檔libhello.c

#include <stdio.h>
void print_hello(void)
{
   printf(“hello library\n”);
}
  • 靜態庫建立步驟二 生成目標檔案libhello.o
$gcc –c libhello.c –o libhello.o
  • 靜態庫建立步驟三 使用ar命令建立靜態庫libhello.a
$ar –rc libhello.a libhello.o
$file libhello.a
  • 靜態庫的使用 編輯測試檔案usehello.c 生成可執行檔案usehello_static
$gcc –o usehello_static usehello.c libhello.a
  • 執行
$./usehello_static

動態庫的建立

  1. 編輯原始檔libhello.h,libhello.c
  2. 生成共享庫目標檔案libhello.o
 $gcc –fPIC –Wall –g
  1. 生成共享庫目標檔案libhello.o
$gcc –fPIC –Wall –g–c libhello.c –o libhello.o 
  1. 編譯共享庫libhello.so.1.0
 $gcc –g –shared –W1,-soname,libhello.so –o libhello.so.1.0 libhello.o 
 $file libhello.so.1.0 
  1. 建立共享庫的符號連線
 $ln –s libhello.so.1.0 libhello.so
  1. 動態庫的使用 編輯測試檔案usehello.c 生成可執行檔案usehello_dy
$gcc –g –o usehello_dy usehello.c –lhello –L ./ 
  1. 執行
$LD_LIBRARY_PATH=$(pwd)  ./usehello_dy

靜態庫與共享庫的區別 可執行檔案大小不同

  • 當多個程序使用同一共享庫,將共享庫中存放的可執行程式碼在記憶體共享;
  • 靜態庫將直接載入到可執行檔案。

共享庫可很大程度上節約系統記憶體。 共享庫發生錯誤,只需要修改當前共享庫,無需重新編譯每個使用該庫的程式

多個原始檔編譯

$gcc foo1.c foo2.c -o foo

解釋:對於原始檔不止一個情況,GCC編譯過程仍然按照預處理、編譯、彙編和連結的過程依次進行。因此,上面這條命令相當於依次執行如下三條命令。

$gcc -c foo1.c -o foo1.o 
$gcc -c foo2.c -o foo2.o 
$gcc foo1.o foo2.o -o foo

GCC選項彙總 在這裡插入圖片描述

GCC選項——-I dir選項 在當前路徑下有檔案hello1.c ,“/root/work/gcc/”目錄下有my.h: 編譯命令:

$gcc hello1.c -I /root/work/gcc/ -o hello1

GCC選項——==-L dir ==選項 “-L dir”的功能與“-I dir”類似,能夠在庫檔案的搜尋路徑列表中新增dir目錄。例如有程式hello2.c需要用到目錄“/root/work/gcc/lib/” /下的一個動態庫libxch.so,則只需鍵入如下命令即可:

$gcc hello2.c –L root/work/gcc/lib/ hello2

注意:“-I dir”和“-L dir”都只是指定了路徑,而沒有指定檔案,因此不能在路徑中包含檔名。

除錯—GDB

GDB概述

對於Linux程式設計師來講,GDB(GNU Debugger)通過與GCC的配合使用,為基於Linux的軟體開發提供了一個完善的除錯環境。 將除錯符號插入到生成的二進位制程式碼中的gcc編譯

$gcc -g hello.c -o hello 

GDB除錯舉例

#【GDBTest.c】
#include <stdio.h>
void sum(int m);
int main()
{
   int i,n=0;
   sum(50);
   for(i=1; i<=50; i++)
   {
      n += i;
   }
   printf("The sum of 1-50 is %d \n", n );
   return(0);
}
void sum(int m)
{
   int i,n=0;
   for(i=1; i<=m;i++) n += i;
   printf("The sum of 1-m is %d\n", n);
}
  1. 首先使用GCC對test.c進行編譯。 注意:GDB進行除錯的是可執行檔案,而不是如“.c”的原始碼,因此,需要先通過GCC編譯生成可執行檔案才能用GDB進行除錯。編譯時一定要加上選項“-g”,這樣編譯出的可執行程式碼中才包含除錯資訊,否則Gdb無法載入該可執行檔案。
$gcc -g test.c -o test
  1. 進入GDB除錯環境
$gdb test

在這裡插入圖片描述

  1. 檢視程式原始檔 (gdb) list 在這裡插入圖片描述

  2. 設定斷點 (gdb) break 6 在這裡插入圖片描述

  3. 檢視斷點設定情況 (gdb) info b 在這裡插入圖片描述

  4. 執行程式 (gdb) run 在這裡插入圖片描述

  5. 檢視變數值 (gdb) print n (gdb) print i 在這裡插入圖片描述

  6. 單步執行 (gdb)next 在這裡插入圖片描述 (gdb)step

  7. 恢復程式執行 (gdb) c 在這裡插入圖片描述

GDB除錯選項

  • GDB的命令可以通過檢視help進行查詢 (gdb) help (gdb) help data (gdb) help call
  • GDB中的命令主要分為以下幾類: 1.工作環境相關命令; 2.設定斷點與恢復命令; 3.原始碼檢視命令; 4.檢視執行資料相關命令及修改執行引數命令。
  • 工作環境相關命令 在這裡插入圖片描述
  • 斷點設定與恢復命令 在這裡插入圖片描述 1.函式斷點 (gdb) break sum 2.條件斷點 (gdb) break 8 if i= =10
  • 原始碼檢視相關命令 在這裡插入圖片描述
  • 檢視執行資料相關命令 在這裡插入圖片描述
  • 修改執行引數相關命令 1.修改執行時的引數,並使該變數按照使用者當前輸入的值繼續執行。設定方法:在單步執行的過程中,鍵入命令“set 變數=設定值” 在這裡插入圖片描述

GNU make

make簡介

Make工程管理器

  1. 一個“自動編譯管理器”
  • GNU的make能夠使整個軟體工程的編譯、連結只需要一個命令就可以完成。
  • “自動”是指它能夠根據檔案時間戳自動發現更新過的檔案而減少編譯的工作量。
  1. Linux程式設計師必須學會使用GNU make 來構建和管理自己的軟體工程。

常用的make命令列選項 在這裡插入圖片描述

Makefile

  1. Make在執行時需要一個命名為Makefile的檔案
  2. Makefile是一個文字形式的資料庫檔案
  • 描述了整個工程的編譯、連結等規則
  • 工程中的哪些檔案需要編譯,具體怎麼編譯
  • 需要建立哪些庫檔案以及如何建立這些庫檔案
  • 如何產生我們最後想要得到的可執行檔案
  1. make在執行時就會找到Makefile檔案

Makefile例項 在這裡插入圖片描述

makefile的編寫

Makefile術語

  1. 規則 用於說明如何產生一個或者多個目標檔案 規則格式:
target: dependency
	COMMAND

例項 在這裡插入圖片描述 注意:在command前面有tab,這個不可缺少

  • 偽目標 Makefile中把那些沒有任何依賴只有執行動作的目標稱為“偽目標” 例項 在這裡插入圖片描述 “.PHONY”將“clean”目標宣告為偽目標
  • 變數 在這裡插入圖片描述 在這裡插入圖片描述
  1. Makefile其他變數 除前面介紹的使用者自定義變數(如OBJS、HDRS)外,make也允許使用環境變數、自動變數和預定義變數。
  • 環境變數——工作環境的相關變數,如路徑、時間等。

  • 自動變數——用於代表編譯語句中出現的目標檔案和依賴檔案,並且具有本地含義。

  • 預定義變數——通常指編譯器、彙編器的名稱及其編譯選項。

  1. 系統預設自動變數 在這裡插入圖片描述 自動變數使用示例 在這裡插入圖片描述

  2. 預定義變數 在這裡插入圖片描述

  3. 隱式規則 Make會自動搜尋隱式規則目錄來確定如何生成檔案。 舉例 在這裡插入圖片描述 常見隱式規則 在這裡插入圖片描述

  4. 模式規則 模式規則是用來定義相同處理規則的多個檔案的。它不同於隱式規則,隱式規則僅僅能夠用make預設的變數來進行操作,而模式規則還能引入使用者自定義變數,為多個檔案建立相同的規則,從而簡化Makefile的編寫。 模式規則的格式類似於普通規則,這個規則中的相關檔案前必須用“%”標明。 在這裡插入圖片描述 在這裡插入圖片描述

  5. Makefile註釋 makefile檔案中只有行註釋,其註釋用“#”字元,就像C語言中的“//”,如果要在makefile檔案中使用“#”字元,可以使用“\”進行轉義,即“#”。

  6. Makefile-函式

$(subst  from,to,text)
功能:在文字text中使用to替換每一處form。
舉例:$(subst  ee,EE,feet on the street)
$(patsubst  pattern,replacement,text)
功能:尋找text中符合pat的字,並repl替換它們。
舉例:$(patsubst  %.c,%.o,x.c.c  bar.c)
$(filter pattern……,text)
功能:返回在text中有空格隔開並匹配pat的字。
舉例:sources := foo.c bar.c bar.s ug.h
		         foo:$(sources)
			    cc  $(filter %.c %.s,$(sources))  -o  foo
$(filter-out  pattern……,text)
$(wildcard pattern)
功能:尋找與格式匹配且檔案存在的檔名
舉例:$(wildcard  %.c  ../src/%.c)
$(addprefix  prefix,names……)
功能:將prefix附加在每一個獨立檔名的前面。
舉例:$(addprefix  src/,foo bar)