日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Unix 环境高级编程(一):开发环境

發布時間:2023/12/16 编程问答 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Unix 环境高级编程(一):开发环境 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Unix 環境高級編程(一):開發環境

  • 一、Unix操作系統
  • 二、Linux操作系統
  • 三、GNU編譯工具(GCC)
    • 1、簡介
    • 2、基本用法
    • 3、文件后綴
    • 4、構建過程
    • 5、預處理指令
    • 6、預定義宏
    • 7、環境變量
  • 四、靜態庫
    • 1、簡介
    • 2、創建靜態庫
    • 3、ar 指令
    • 4、調用靜態庫
  • 五、共享庫
    • 1、簡介
    • 2、創建共享庫
    • 3、調用共享庫
    • 3、運行
  • 六、動態加載共享庫
    • 1、頭文件
    • 2、加載共享庫
    • 3、獲取函數地址
    • 4、卸載共享庫
    • 5、 獲取錯誤信息
  • 七、輔助工具

一、Unix操作系統

二、Linux操作系統

三、GNU編譯工具(GCC)

1、簡介

??GCC是以GPL許可證所發行的自由軟件,也是GNU計劃的關鍵部分。GCC的初衷是為GNU操作系統專門編寫一款編譯器,現已被大多數類Unix操作系統(如Linux、BSD、MacOS X等)采納為標準的編譯器,甚至在微軟的Windows上也可以使用GCC。GCC支持多種計算機體系結構芯片,如x86、ARM、MIPS等,并已被移植到其他多種硬件平臺。

??GCC原名為GNU C語言編譯器(GNU C Compiler),只能處理C語言。但其很快擴展,變得可處理C++,后來又擴展為能夠支持更多編程語言,如Fortran、Pascal、Objective -C、Java、Ada、Go以及各類處理器架構上的匯編語言等,所以改名GNU編譯器套件(GNU Compiler Collection)。

2、基本用法

gcc [options] [filenames] /* GCC最基本的用法是∶gcc [options] [filenames] * 其中 options 就是編譯器所需要的參數* filenames 給出相關的文件名稱* */-c /* 只編譯,不鏈接成為可執行文件,* 編譯器只是由輸入的.c等源代碼文件生成.o為后綴的目標文件,* 通常用于編譯不包含主程序的子程序文件 * */-o /* output_filename,確定輸出文件的名稱為output_filename,* 同時這個名稱不能和源文件同名。* 如果不給出這個選項,gcc就給出預設的可執行文件a.out * */-x /* 設定文件所使用的語言, 使后綴名無效, 對以后的多個有效* 根據約定 C 語言的后綴名稱是 .c 的,* 而 C++ 的后綴名是 .C 或者 .cpp, * 如果你很個性,決定你的 C 代碼文件的后綴名是 .pig ,* 那你就要用這個參數, 這個參數對他后面的文件名都起作用,* 除非到了下一個參數的使用* */-I /* Idirname,* 將dirname所指出的目錄加入到程序頭文件目錄列表中,* 是在預編譯過程中使用的參數 * */-E /* 只激活預處理,這個不生成文件, * 你需要把它重定向到一個輸出文件里面 * */-S /* 只激活預處理和編譯,就是指把文件編譯成為匯編代碼 */-g /* 產生符號調試工具(GNU的gdb)所必要的符號資訊,* 要想對源代碼進行調試,我們就必須加入這個選項* */-O /* 對程序進行優化編譯、鏈接,* 采用這個選項,整個源代碼會在編譯、鏈接過程中進行優化處理,* 這樣產生的可執行文件的執行效率可以提高,* 但是,編譯、鏈接的速度就相應地要慢一些 * */-v /* gcc執行時執行的詳細過程,gcc及其相關程序的版本號 */-pedantic /* 對不符合ANSI/ISO C語言標準的擴展語法產生警告 */-Wall /* 產生盡可能多的警告 */-Werror /* 將警告作為錯誤處理 */

3、文件后綴

.c /* C語言源代碼文件 */.h /* 程序所包含的頭文件 */.i /* 預處理后的C語言源代碼文件 */.s /* 匯編語言文件 */.S /* 經過預編譯的匯編語言源代碼文件 */.o /* 編譯后的目標文件 */.a /* 靜態庫文件 */.so /* 共享庫(動態庫)文件 */

4、構建過程

編輯 -> 預編譯(預處理)-> 編譯 -> 匯編 -> 鏈接

  • 編輯(hello.c)
  • /* 使用 vim 編輯器編寫代碼 */ vim hello.c
  • 預編譯(hello.i)
  • /* 使用 -E 選項,生成 .i 預編譯文件* 這個過程處理宏定義和include,去除注釋,不會對語法進行檢查*/ gcc -E hello.c -o hello.i
  • 編譯(hello.s)
  • /* 使用 -S 選項,生成 .s 匯編文件* 這個階段,檢查語法*/ gcc -S hello.i
  • 匯編(hello.o)
  • /* 使用 -c 選項,生成 .o 目標文件 */ gcc -c hello.s
  • 鏈接(hello)
  • /* 使用 -o 選項,生成可執行文件 */ gcc hello.o -o hello

    5、預處理指令

    #include // 將指定文件的內容插至此指令處 #include_next // 與#include一樣,但從當前目錄之后的目錄查找,極少用 #define // 定義宏 #undef // 刪除宏 #if // 判定 #ifdef // 判定宏是否已定義 #ifndef // 判定宏是否未定義 #else // 與#if、#ifdef、#ifndef結合使用 #elif // else if多選分支 #endif // 結束判定 ## // 連接宏內兩個連續的字符串 # // 將宏參數擴展成字符串字面值 #error // 產生錯誤,結束預處理 #warning // 產生警告 #pragma // 提供額外信息的標準方法,可用于指定平臺 #pragma GCC dependency <文件> // 若<文件>比此文件新則產生警告 #pragma GCC poison <標識> // 若出現<標識>則產生錯 誤 #pragma pack(1/2/4/8) // 按1/2/4/8字節對齊補齊 #line // 指定行號

    For example:

  • error.c
  • #include <stdio.h>#if (VERSION < 1)#error "Version is too low!" #elif (VERSION > 4)#warning "version is too high!" #endifint main(void) {printf("Version is :%d\n", VERSION);return 0; }

  • line.c
  • #include <stdio.h>int main(void) {printf("line is %d\n", __LINE__); #line 100printf("line is %d\n", __LINE__); return 0; }

  • pragma.c
  • #include <stdio.h>#pragma GCC dependency "tmp.c" // 若tmp.c比此文件新則產生警告int main(void) {return 0; }

    #include <stdio.h>#pragma GCC poison goto float // 若出現 goto 或 float 則產生錯誤int main(void) {float a;loop :goto loop;return 0; }

    /* 64位操作系統下,默認8字節對齊 */ #include <stdio.h>#pragma pack(1)struct S1 {double d;char c;int i;short h;}; // DDDDDDDDCIIIIHH, 15 #pragma pack(4)struct S2 {double d;char c;int i;short h;}; // DDDDDDDDCXXXIIIIHHXX, 20 #pragma pack(8)struct S3 {double d;char c;int i;short h;}; // DDDDDDDDCXXXXXXXIIIIHHXX, 24int main(void) { #pragma pack()printf ("S1: %lu字節\n", sizeof (struct S1));printf ("S2: %lu字節\n", sizeof (struct S2));printf ("S3: %lu字節\n", sizeof (struct S3));return 0; }

    6、預定義宏

    __BASE_FILE__ // 正在編譯的源文件名 __FILE__ // 所在文件名 __LINE__ // 行號 __FUNCTION__ // 函數名 __func__ // 同__FUNCTION__ __DATE__ // 日期 __TIME__ // 時間 __INCLUDE_LEVEL__ // 包含層數,從0開始 __cplusplus // C++編譯器將其定義為1,// C編譯器不定義該宏

    For example:

  • print.h
  • #ifndef _PRINT_H #define _PRINT_H#include <stdio.h>void print (void) {printf ("__BASE_FILE__ : %s\n", __BASE_FILE__);printf ("__FILE__ : %s\n", __FILE__);printf ("__LINE__ : %d\n", __LINE__);printf ("__FUNCTION__ : %s\n", __FUNCTION__);printf ("__func__ : %s\n", __func__);printf ("__DATE__ : %s\n", __DATE__);printf ("__TIME__ : %s\n", __TIME__);printf ("__INCLUDE_LEVEL__ : %d\n", __INCLUDE_LEVEL__); #ifdef __cplusplusprintf ("__cplusplus : %d\n", __cplusplus); #endif // __cplusplus }#endif//_PRINT_H
  • predef.h
  • #ifndef _PREDEF_H #define _PREDEF_H#include "print.h"#endif//_PREDEF_H
  • predef.c
  • #include "predef.h"int main (void) {print ();return 0; }


    7、環境變量

    C_INCLUDE_PATH // C頭文件的附加搜索路徑,相當于gcc的-I選項 CPATH // 同C_INCLUDE_PATH CPLUS_INCLUDE_PATH // C++頭文件的附加搜索路徑 LIBRARY_PATH // 鏈接時查找靜態庫/共享庫的路徑 LD_LIBRARY_PATH // 運行時查找共享庫的路徑
  • 通過gcc的-I選項指定C/C++頭文件的附加搜索路徑
  • gcc calc.c cpath.c -I.
  • 將當前目錄作為C頭文件附加搜索路徑,添加到CPATH環境變量中
  • export CPATH=$CPATH:. // export保證當前shell的,子進程繼承此環境變量 echo $CPATH env | grep CPATH
  • 也可以在/.bashrc或/.bash_profile,配置文件中寫環境變量,永久有效
  • export CPATH=$CPATH:. 執行 # source ~/.bashrc 或 # source ~/.bash_profile //生效,以后每次登錄自動生效。
  • 頭文件的三種定位方式
    a)#include “目錄/xxx.h”
    ??頭文件路徑發生變化,需要修改源程序
    b)C_INCLUDE_PATH/CPATH=目錄
    ??同時構建多個工程,可能引發沖突
    c)gcc -I目錄
    ??既不用改程序,也不會有沖突
  • 頭文件的作用
    a)聲明外部變量、函數和類
    b)定義宏、類型別名和自定義類型
    c)包含其它頭文件
    d)借助頭文件衛士,防止因同一個頭文件被多次包含,而引發重定義錯
  • 包含頭文件時需要注意的問題
    a)gcc的-I選項
    ??指定頭文件附加搜索路徑
    b)#include <…>
    ??先找-I指定的目錄,再找系統目錄
    c)#include “…”
    ??先找-I指定的目錄,再找當前目錄,最后找系統目錄
    d)頭文件的系統目錄
  • /usr/include /usr/local/include /usr/lib/gcc/x86_64-linux-gnu/5.4.0/include

    四、靜態庫

    1、簡介

  • 鏈接靜態庫是將庫中的被調用代碼復制到調用模塊中
  • 靜態庫占用空間非常大,不易修改但執行效率高
  • 靜態庫的缺省擴展名是.a
  • 2、創建靜態庫

  • 編輯源代碼
  • vim xxx.c/xxx.h
  • 編譯成目標文件
  • gcc -c xxx.c -o xxx.o
  • 打包成靜態庫文件
  • ar -r libxxx.a xxx.o ...

    3、ar 指令

    ar指令:ar [選項] 靜態庫文件名 目標文件列表 -r // 將目標文件插入到靜態庫中,已存在則更新 -q // 將目標文件追加到靜態庫尾 -d // 從靜態庫中刪除目標文件 -t // 列表顯示靜態庫中的目標文件 -x // 將靜態庫展開為目標文件 /* 注意:提供靜態庫的同時也需要提供頭文件 */

    4、調用靜態庫

  • 直接調用
  • gcc main.c libxxx.a
  • 通過LIBRARY_PATH環境變量指定庫路徑
  • export LIBRARY_PATH=$LIBRARY_PATH:. gcc main.c -lmath (環境法)
  • 通過gcc的-L選項指定庫路徑
  • unset LIBRARY_PATH gcc main.c -lmath -L. (參數法)
  • 一般化的方法:
  • gcc .c/.o -l<庫名> -L<庫路徑>
  • 運行
    ??在可執行程序的鏈接階段,已將所調用的函數的二進制代碼,復制到可執行程序中,因此運行時不需要依賴靜態庫。
  • 五、共享庫

    1、簡介

  • 鏈接共享庫則只是在調用模塊中,嵌入被調用代碼在庫中的(相對)地址
  • 共享庫占用空間小,易于修改但執行效率略低
  • 共享庫的缺省擴展名是.so
  • 2、創建共享庫

  • 編輯源程序
  • vim xxx.x/xxx.h
  • 編譯成目標文件
  • gcc -c -fpic xxx.c
  • 鏈接成共享庫文件
  • gcc -shared xxx.o -o libxxx.so
  • PIC (Position Independent Code)
    ??位置無關代碼。可執行程序加載它們時,可將其映射到其地址空間的任何位置。
  • -fPIC // 大模式,生成代碼比較大,運行速度比較慢,所有平臺都支持。 -fpic // 小模式,生成代碼比較小,運行速度比較快,僅部分平臺支持。 /* 注意:提供共享庫的同時也需要提供頭文件 */

    3、調用共享庫

  • 直接調用
  • gcc main.c libxxx.so
  • 通過LIBRARY_PATH環境變量指定庫路徑
  • export LIBRARY_PATH=$LIBRARY_PATH:. gcc main.c -lmath (環境法)
  • 通過gcc的-L選項指定庫路徑
  • unset LIBRARY_PATH gcc main.c -lmath -L. (參數法)
  • 一般化的方法
  • gcc .c/.o -l<庫名> -L<庫路徑>

    3、運行

    ??運行時需要保證LD_LIBRARY_PATH,環境變量中包含共享庫所在的路徑。
    ??在可執行程序的鏈接階段,并不將所調用函數的二進制代碼復制到可執行程序中。
    ??而只是將該函數在共享庫中的地址嵌入到可執行程序中,因此運行時需要依賴共享庫。
    ??gcc缺省鏈接共享庫,可通過-static選項強制鏈接靜態庫。

    六、動態加載共享庫

    1、頭文件

    #include <dlfcn.h>

    2、加載共享庫

    /* * 返回值: * 成功返回共享庫句柄,失敗返回NULL。 * * 參數: * filename:共享庫路徑 * 若只給文件名,則根據LD_LIBRARY_PATH環境變量搜索。 * flag取值:加載方式 * RTLD_LAZY - 延遲加載,使用共享庫中的符號 (如調用函數)時才加載。 * RTLD_NOW - 立即加載。 */ void* dlopen (const char* filename, int flag);

    3、獲取函數地址

    /** 返回值:* 成功返回函數地址,失敗返回NULL。* * 參數:* hanedle:共享庫句柄* symbol:函數名*/ void* dlsym (void* handle,const char* symbol );

    4、卸載共享庫

    /** 成功返回0,失敗返回非零。*/ int dlclose (void* handle);

    5、 獲取錯誤信息

    /** 有錯誤發生則返回錯誤信息字符串指針,否則返回NULL。*/ char* dlerror (void);

    七、輔助工具

    總結

    以上是生活随笔為你收集整理的Unix 环境高级编程(一):开发环境的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。