天天看點

Linux的程序環境

一、指令行參數

當執行一個程式時,調用exec的程序可将指令行參數傳遞給該新程式。注意:通常echo(1)程式不回顯第0個程式。

【例】将所有指令行參數回顯到标準輸出

Linux的程式環境

注:ISO和POSIX.1都要求argv[argc]是一個空指針。這就使得我們可以将參數處理循環改寫為:for(i = 0; argv[i] != NULL; i++)。其中,argc是指令行參數的數目,argv是指向參數的各個指針所構成的數組。

二、環境表

每個程式都接收到一張環境表。與參數表一樣,環境表也是一個字元指針數組,其中每個指針包含一個以null結束的C字元串的位址。全局變量environ則包含了該指針數組的位址:extern char **environ。

【例】如果該環境包含5個字元串,那麼它看起來如下圖所示:

Linux的程式環境

釋:

1)每個字元串的結尾處都顯示的有一個null位元組。

2)environ為環境指針(environment pointer),指針數組為環境表,其中各指針指向的字元串為環境字元串。

3)用getenv和putenv函數來通路特定的環境變量,而不是用environ變量。但是,如果要檢視整個環境,則必須用environ指針。

三、C程式的存儲空間分布

其組成在空間中的分布,如下圖所示:

Linux的程式環境

1、正文段:由CPU執行的機器指令部分,是共享的、隻可讀的。

2、初始化資料段:通常此段稱為資料段,它包含了程式中需明确賦初值的變量。

3、未初始化資料段:通常此段稱為bss段,在程式開始執行之前,核心将此段中的資料初始化為0或空指針。

4、棧:

(1)自動變量以及每次函數調用時所需儲存的資訊都儲存在此段中。

(2)每次函數函數調用時,其傳回位址及調用者的環境資訊。

注意:每次遞歸函數調用自身時,就用一個新的棧幀,是以一次函數調用執行個體中的變量集不會影響另一次函數調用中的執行個體。

5、堆:位于未初始化資料段和棧之間,堆頂和棧頂之間的。程式通常在堆中進行動态配置設定。

6、注意:

(1)未初始化資料段的内容并不存放在磁盤檔案程式中,其原因是:核心在程式開始運作前将他們都設定為0,需要存放在磁盤檔案中的段隻有正文段和初始化資料 段。

(2)a.out中還有若幹其他類型的段,如

1)符号表的段;

2)調試資訊的段;

3)動态共享庫連結表的段

7、計算各段的長度

【例】Size指令計算正文段、資料段和bss段的長度(以位元組為機關)。

Linux的程式環境

釋:第四列和第五列分别表示十進制和十六進制表示的3段總長度。

四、共享庫

1、使用說明

共享庫使得可執行檔案中不再需要包含公用的庫函數,而隻需在所有程序都可引用的存儲區中儲存這種庫例程的一個副本。

2、使用共享庫的優點

(1)程式第一次執行或者第一次調用某個庫函數時,用動态連結方法将程式與共享庫函數相連接配接,可減少每個執行檔案的長度,但是會增加運作時間的開銷。這種時間的開銷發生在該程式第一次被執行時,或者共享庫函數第一次被調用時。

(2)可以用庫函數的新版本代替舊版本而無需對使用該庫的程式重新連接配接編輯(假定參數的類型和數目都沒有發生變化)。

五、環境變量

1、基本概念:

(1)含義:一般指在作業系統中用來指定作業系統運作環境的一些參數。如:我們編寫C/C++代碼,在連接配接的時候從來不知道所連結的動、靜态庫在哪裡,但是照樣可以連結成功,生成可執行程式。原因是:有關環境變量幫助編譯器進行查找。

(2)性質:具有全局特性。

2、常用環境變量

(1)PATH*:指定指令的搜尋路徑。

(2)HOME*:指定使用者的主工作目錄,即使用者登入到Linux系統中時預設的目錄。

(3)HISTSIZE*:指儲存曆史指令記錄的條數。

(4)SHELL*:目前Shell,它的值通常是/bin/bash。

3、檢視PATH

echo $NAME//NAME指環境變量名

【例】

Linux的程式環境

4、測試環境變量

(1)測試PATH

(2)測試HOME

(3)測試HISTSIZE

5、和環境變量相關的指令

(1)echo:顯示某個環境變量值。

(2)export:設定一個新的環境變量。

(3)env:顯示所有的環境變量。

(4)set:顯示本地定義的Shell變量和環境變量。

6、通過代碼擷取環境變量

【例1】擷取指令行的第三個參數

[hongji@localhost ]$ cat -n argv1.c
       #include<stdio.h>
       #include<stdlib.h>
       
       int main(int argc, char *argv[], char *env[])
       {
           int i = ;
           for(; env[i]; i++){
               printf("%s\n", env[i]);
           }
          return ;
      }
           

運作結果:

Linux的程式環境

【例2】通過第三方變量environ擷取

[[email protected] _23]$ cat -n environ1.c 
       #include<stdio.h>
       #include<stdlib.h>
       
       int main(int argc, char *argv[])
       {   
           extern char **environ;
           int i = ;
           for(; environ[i]; i++){
               printf("%s\n", environ[i]);
          }
          return ;
      }   
           

運作結果:

Linux的程式環境

釋:libc中定義的全局變量environ指向環境變量表,environ沒有包含在任何頭檔案中,是以在使用時要用extern聲明。

【例3】通過系統調用擷取或設定環境變量

[hongji@localhost ]$ cat -n getenv1.c 
       #include<stdio.h>
       #include<stdlib.h>
       
       int main()
       {
           printf("%s\n", getenv("PATH"));
           return ;
       }
           

運作結果:

Linux的程式環境

【例4】環境變量具有全局屬性,可以被子程序繼承下去

Linux的程式環境

分析:

1)直接檢視,發現沒有結果,說明該環境變量根據不存在。

2)如果導出環境變量:export MYENV=”hello world”,再次運作程式,發現結果有了。說明:環境變量是可以繼承下去的。

3)如果隻進行MYENV=”hello world”,不調用export導出,再用程序檢視會有什麼結果?結果如下圖所示:

釋:因為不調用export,能到的隻是普通變量。

繼續閱讀