跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C

进程概念详解:命令行参数、环境变量与地址空间

命令行参数与环境变量是进程交互的重要桥梁。深入解析了 argc/argv 机制、环境变量作用域及持久化方法,并通过 fork 实验验证了进程内存隔离性。最后结合 readelf 剖析了程序地址空间的物理布局,涵盖代码、数据、堆栈等关键区域。

DataScient发布于 2026/3/16更新于 2026/7/2338 浏览
进程概念详解:命令行参数、环境变量与地址空间

4. 命令行参数和环境变量

程序启动时,操作系统会传递一些信息给 main 函数,这就是命令行参数。同时,进程还携带着一套环境配置,即环境变量。

命令行参数 (argc, argv)

在 Linux 终端下编译并运行一个简单的 C 程序,观察参数的传递过程。

gsm@VM-4-3-centos lesson13$ ls -l
total 16
-rwxrwxr-x 1 gsm gsm 8360 Oct 28 22:35 a.out
-rw-rw-r-- 1 gsm gsm 258 Oct 28 22:35 test.c

编写一个接收参数的程序 code.c:

#include <stdio.h>

int main(int argc, char* argv[]) {
    printf("argc: %d\n", argc);
    for (int i = 0; i < argc; i++) {
        printf("argv[%d]: %s\n", i, argv[i]);
    }
    return 0;
}

注意,C99 标准之前不支持在 for 循环中声明变量,编译时需加上 -std=c99 选项。

gsm@VM-4-3-centos lesson13$ make gcc -o code code.c -std=c99

运行测试:

gsm@VM-4-3-centos lesson13$ ./code
argc: 1
argv[0]: ./code

gsm@VM-4-3-centos lesson13$ ./code 1 2 3
argc: 4
argv[0]: ./code
argv[1]: 1
argv[2]: 2
argv[3]: 3

可以看到,argv[0] 永远是程序名本身,后续才是用户输入的参数。我们可以利用这一点实现类似 ./program --help 的功能。

命令行参数

环境变量 (Environment Variables)

环境变量是进程运行时的全局配置,通过 getenv 函数获取,或通过 environ 指针数组直接访问。

#include <stdio.h>


  {
    
     ** environ;
     ( i = ; environ[i]; i++) {
        (, environ[i]);
    }
     ;
}
#include <stdlib.h>
int
main
()
// 遍历所有环境变量
extern
char
for
int
0
printf
"%s\n"
return
0

运行后你会看到大量的键值对,如 PATH, HOME, USER 等。其中 PATH 决定了系统在哪里查找可执行命令。

PATH 的作用域

修改 PATH 可以临时改变当前 Shell 的搜索路径,但不会影响其他进程或持久化。

gsm@VM-4-3-centos lesson13$ echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/gsm/.local/bin:/home/gsm/bin

gsm@VM-4-3-centos lesson13$ PATH=/home/gsm/linux/112/lesson13

gsm@VM-4-3-centos lesson13$ code
# 如果 code 在当前目录且 PATH 已包含该目录,则能直接运行

若想让修改永久生效,需要写入 .bash_profile 或 .bashrc 并使用 export 关键字。

gsm@VM-4-3-centos ~$ vim .bash_profile
# ... 添加 export PATH=$PATH:/home/gsm/linux/112/lesson13 ...
gsm@VM-4-3-centos ~$ source .bash_profile
区分用户身份

环境变量中的 USER 字段常用于判断当前操作者。例如,限制脚本仅允许特定用户运行。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    const char* who = getenv("USER");
    if (strcmp(who, "gsm") == 0) {
        printf("执行程序的正常命令!\n");
        return 0;
    } else {
        printf("无权访问!\n");
        return 1;
    }
}

环境变量(1)

此外,OLDPWD 记录了上一次所在的目录,配合 cd - 命令使用非常方便。

环境变量(2)

5. 程序地址空间

每个进程都有独立的虚拟内存空间,通常分为代码段、数据段、BSS 段、堆和栈。

父子进程的内存独立性

通过 fork() 创建子进程后,虽然初始内存布局相同,但父子进程拥有独立的地址空间。修改子进程的全局变量不会影响父进程。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int gval = 100;

int main() {
    printf("我是父进程,pid: %d, ppid: %d, gval: %d, &gval: %p\n", getpid(), getppid(), gval, &gval);
    pid_t id = fork();
    if (id == 0) {
        // 子进程
        while (1) {
            printf("我是子进程,pid: %d, gval: %d, &gval: %p\n", getpid(), gval, &gval);
            gval++;
            sleep(1);
        }
    } else {
        // 父进程
        while (1) {
            printf("我是父进程,pid: %d, gval: %d, &gval: %p\n", getpid(), gval, &gval);
            sleep(1);
        }
    }
    return 0;
}

运行结果会显示,尽管 &gval 的地址可能相同(虚拟地址),但实际物理内存已被隔离,子进程自增 gval 时,父进程的 gval 保持不变。

程序地址空间(1)

内存布局分析

我们可以通过打印不同变量的地址来直观感受内存分布:

#include <stdio.h>
#include <stdlib.h>

int unval;      // BSS 段
int gval = 100; // 数据段

int main() {
    printf("code addr: %p\n", main);           // 代码段
    printf("gval addr: %p\n", &gval);          // 数据段
    printf("unval addr: %p\n", &unval);        // BSS 段
    
    int* mem = (int*)malloc(10 * sizeof(int)); // 堆
    printf("heap addr: %p\n", mem);
    
    int a, b, c;                               // 栈
    printf("stack addr: %p\n", &a);
    printf("stack addr: %p\n", &b);
    printf("stack addr: %p\n", &c);
    return 0;
}

典型输出如下:

code addr: 0x40057d       # 低地址
...                       # 数据段/BSS
heap addr: 0x890010       # 堆
stack addr: 0x7ffc8e34df54 # 高地址

结合 readelf 工具查看 ELF 文件结构,可以更清晰地看到各段在二进制文件中的位置。

gsm@VM-4-3-centos lesson14$ readelf -S process
There are 30 section headers...
[Nr] Name Type Address Offset Size ...
[13].text PROGBITS 0000000000400490 ... # 代码段
[24].data PROGBITS 0000000000601038 ... # 数据段
[25].bss NOBITS 0000000000601040 ...   # BSS 段

程序地址空间(2) 程序地址空间(3) 程序地址空间(4)

目录

  1. 4. 命令行参数和环境变量
  2. 命令行参数 (argc, argv)
  3. 环境变量 (Environment Variables)
  4. PATH 的作用域
  5. 如果 code 在当前目录且 PATH 已包含该目录,则能直接运行
  6. ... 添加 export PATH=$PATH:/home/gsm/linux/112/lesson13 ...
  7. 区分用户身份
  8. 5. 程序地址空间
  9. 父子进程的内存独立性
  10. 内存布局分析
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 万方 AIGC 检测未通过?多款降 AI 工具实测效果分析
  • 33 岁前端女性开发者失业后的转行方向建议
  • OpenClaw 多飞书机器人与多 Agent 团队实战复盘
  • GitHub Copilot 账号被封禁处理指南
  • 飞算 JavaAI 插件辅助生成 Java 项目实战
  • 6 款 AI 写作工具实测:网文创作哪款更顺手?
  • 汇川机器人软件 RobotLab 常规操作
  • C++11 新特性详解:Lambda 表达式、可变参数模板与包装器
  • AI + 鸿蒙游戏:会是下一个爆点?
  • Git 在 Windows 上的安装与配置完整指南
  • AI 提示词:零基础入门与核心概念
  • Java 面向对象核心:继承、多态与抽象类接口
  • 2026年最新版 Dev C++ 下载安装与配置完整教程
  • 数据结构:递归算法核心原理与实现
  • Trae、Cursor、Copilot、Windsurf 四款 AI 编程工具对比
  • 大模型工程化与传统 AI 工程的核心差异解析
  • Whisper OpenAI 开源语音识别工具安装与使用指南
  • 7款国内AI助手横评:豆包、元宝、千问、Kimi、DeepSeek、MiniMax、GLM
  • 本地 AI 绘图实战:Z-Image-Turbo_UI 界面体验与性能测试
  • 基于FPGA与MATLAB的超声多普勒频移解调应用

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online