前言:歡迎各位光臨本博客,這里小編帶你直接手撕Linux程序地址空間,文章并不復雜,愿諸君耐其心性,忘卻雜塵,道有所長!!!!
**🔥個人主頁:IF’Maxue-CSDN博客
🎬作者簡介:C++研發方向學習者
📖**個人專欄:
《C語言》
《C++深度學習》
《Linux》
《數據結構》
《數學建模》**??人生格言:生活是默默的堅持,毅力是永久的享受。不破不立,遠方請直行!
文章目錄
- 一、環境變量:系統的“運行說明書”
- 1. 為什么系統命令不用“找路”?靠PATH!
- 2. 環境變量從哪來?bash“讀配置”來的
- 3. 常用環境變量:記這幾個就夠了
- 4. 操作環境變量:3個常用命令
- 5. 代碼里怎么獲取環境變量?3種方法
- 方法1:main函數的第三個參數envp
- 方法2:getenv函數(推薦!)
- 方法3:全局變量environ
- 二、程序地址空間:不是內存,是“虛擬地圖”
- 1. C程序的地址空間劃分
- 2. 關鍵:程序地址空間 ≠ 物理內存
一、環境變量:系統的“運行說明書”
你可以把環境變量理解成Linux系統的“小記事本”——里面記滿了程序運行、系統操作需要的關鍵信息,比如“去哪找你要運行的程序”“現在登錄的是誰”“當前在哪個文件夾”,有了它,系統和程序才知道該“怎么干活”。
1. 為什么系統命令不用“找路”?靠PATH!
你有沒有好奇過:輸入ls
“列出文件”、pwd
“看當前路徑”時,為什么不用像自己寫的程序那樣輸全路徑(比如/home/xxx/myprogram
)?答案就是PATH環境變量。
- PATH的作用:專門記錄“程序存放路徑”的列表。系統執行
ls
這類命令時,會順著PATH里的路徑挨個找,找到對應的程序文件就運行,找不到就提示“命令不存在”。 - 怎么看PATH?用
echo $PATH
(注意$
是“調用環境變量”的符號),就像這張圖里展示的:
圖里用echo $PATH
輸出的一串路徑,就是系統找程序的“地圖”。 - 驗證一下:如果把PATH里的路徑清空(比如
PATH=
),再輸ls
就會提示“找不到命令”;再用PATH=$PATH:/bin
把/bin
(ls
所在的路徑)加回去,ls
又能正常用了,就像這張圖:
如果不小心改壞了PATH也別怕——重啟電腦后,系統會重新加載配置,PATH就恢復原樣了。
2. 環境變量從哪來?bash“讀配置”來的
每次你登錄Linux,系統會啟動一個“命令解釋器”——bash
(就是你輸命令的窗口)。bash不會憑空生成環境變量,而是去讀兩個關鍵配置文件:bashrc
和profile
,從里面加載預設的環境變量。
- 多用戶登錄的情況:如果10個用戶同時登錄Linux,就會啟動10個bash,每個bash都會讀自己的配置文件,所以每個用戶的環境變量可以不一樣,就像這張圖里的調用關系:
3. 常用環境變量:記這幾個就夠了
除了PATH,還有幾個常用的環境變量,用echo $變量名
就能查看,對應這張圖里的內容:
環境變量 | 作用(通俗說) | 例子 |
---|---|---|
USER | 當前登錄的用戶名 | echo $USER 輸出 root 或你的用戶名 |
HISTSIZE | 保存多少條歷史命令 | 默認存1000條,輸過的命令都在這 |
HOSTNAME | 這臺電腦的“名字” | echo $HOSTNAME 看電腦名 |
PWD | 當前所在的文件夾路徑 | 比如在/home ,就輸出/home |
比如這張圖里的PWD,就是當前的路徑:
4. 操作環境變量:3個常用命令
環境變量分兩種:本地變量(只有當前bash能用,子進程用不了)和環境變量(子進程也能繼承),用以下命令切換和操作:
-
export:把本地變量變成環境變量
比如先定義一個本地變量a=123
,這時候運行子進程(比如自己寫的程序)拿不到a
;用export a
之后,a
就變成環境變量,子進程也能訪問了,就像這張圖:
-
unset:刪除環境變量
想刪掉某個環境變量,比如a
,就輸unset a
,之后echo $a
就看不到值了,對應這張圖:
-
set:查看所有變量
輸set
能看到所有本地變量和環境變量,方便排查問題。
5. 代碼里怎么獲取環境變量?3種方法
自己寫C程序時,想拿到系統的環境變量,有3種常用方法:
方法1:main函數的第三個參數envp
main函數其實能接3個參數(不是只有int main()
!),第三個參數envp
是個字符串數組,每個元素都是一個環境變量(格式是“變量名=值”):
#include <stdio.h>
// argc:參數個數,argv:命令行參數,envp:環境變量列表
int main(int argc, char *argv[], char *envp[]) {// 循環打印所有環境變量int i = 0;while (envp[i] != NULL) {printf("%s\n", envp[i]);i++;}return 0;
}
就像這張圖里的main函數參數說明:
方法2:getenv函數(推薦!)
想直接拿某個環境變量(比如PATH),用getenv("變量名")
最方便,返回值就是變量的值:
#include <stdio.h>
#include <stdlib.h> // getenv需要的頭文件int main() {// 拿PATH環境變量的值char *path = getenv("PATH");// 拿USER環境變量的值char *user = getenv("USER");printf("PATH: %s\n", path);printf("USER: %s\n", user);return 0;
}
編譯運行后,就能看到PATH和USER的值,對應這張圖:
方法3:全局變量environ
系統有個全局二級指針environ
,專門存環境變量,需要用extern
聲明后才能用:
#include <stdio.h>// 聲明全局變量environ
extern char **environ;int main() {int i = 0;// 循環打印所有環境變量while (environ[i] != NULL) {printf("%s\n", environ[i]);i++;}return 0;
}
就像這張圖里的environ說明:
二、程序地址空間:不是內存,是“虛擬地圖”
你寫C程序時,可能以為指針指向的是“物理內存地址”——其實不是!程序里的地址都是“虛擬地址”,而“程序地址空間”就是系統給進程畫的一張“虛擬地圖”。
1. C程序的地址空間劃分
C程序運行時,代碼和數據會被分到不同的“區域”,就像這張圖里展示的:
用通俗的話解釋這幾個區域:
- 代碼段:存你的代碼(比如
printf
、main
函數),是“只讀”的——你不能改代碼里的內容,比如字符串常量"hello"
就存在這,像這張圖里說的“字符串被編譯成代碼,只讀”:
- 數據段:存全局變量和
static
變量(比如int g_val = 10;
、static int s_val = 20;
),程序一啟動就分配空間。 - 堆:存你手動申請的內存(比如
malloc(10)
、new int
),需要自己free
或delete
釋放。 - 棧:存函數里的局部變量(比如
int a = 5;
),函數結束后自動釋放。
2. 關鍵:程序地址空間 ≠ 物理內存
很多人會把“程序地址空間”和“物理內存”搞混,其實它們的關系是:
- 程序地址空間 = 虛擬地址空間:是系統給進程分配的“地址范圍”(比如0~4GB),進程以為自己獨占這部分地址。
- 物理內存:電腦里真實的內存條(比如8GB、16GB),系統會把“虛擬地址”轉換成“物理地址”,再去訪問真實內存。
就像這張圖里強調的:C/C++指針用的都是虛擬地址,程序地址空間是“系統概念”,不是“語言概念”:
簡單說:進程拿著“虛擬地址”(地圖上的位置),系統幫它找到“物理地址”(真實的房子),這樣既能保護內存安全(進程看不到彼此的地址),又能高效利用內存。