在 C 里获取当前程序名称,看上去只是一个小问题,实际却和平台能力、运行时实现以及你到底想拿到“文件名”还是“完整路径”直接相关。下面按 Linux、macOS、Windows 以及跨平台场景分别梳理 4 种常见方法,并给出它们的适用范围、返回结果差异和对应示例,读完就能判断自己的场景该用哪一种。
先判断你需要的是程序名还是可执行文件路径
在动手之前,先区分两个目标:
- 程序名:通常只包含文件名,不带完整路径,例如
myapp。 - 可执行文件路径:包含完整位置,例如
/usr/bin/myapp或 Windows 下的完整路径。
这两个目标对应的方法并不一样:
- 只想拿到名称,类 Unix 系统里可以看
__progname。 - 想兼顾不同平台,最常见的是
argv[0]。 - 要拿 Linux 下当前进程对应的可执行文件真实路径,可以读取
/proc/self/exe。 - 要拿 Windows 下的完整路径,直接使用
GetModuleFileName。
方法一:类 Unix 系统使用 __progname
__progname 是一个特殊的全局变量,保存当前正在运行程序的名称。它只适用于类 Unix 系统,比如 Linux、macOS。
它是什么
extern表示这个变量定义在别处,通常由 C 运行时提供。char *__progname表示它是一个指向字符数组的指针,内容是当前可执行文件的名称。__progname一般不是完整路径,而只是文件名。
例如程序路径是 /usr/bin/myapp,那么 __progname 通常就是 myapp。
使用示例
#include <stdio.h>
extern char *__progname;
int main(void) {
printf("This program is called: %sn", __progname);
return 0;
}
适合什么场景
如果你的程序只运行在类 Unix 平台,而且只关心程序名本身,这种方式足够直接。它的问题也很明确:不具备跨平台通用性。
方法二:使用 argv[0],兼顾跨平台
argv[0] 是获取程序名称时最常见、也最通用的办法,类 Unix 和 Windows 都可以使用。
为什么它最常见
因为这是从 main 函数参数直接拿到的信息,不依赖特定平台 API,也不依赖某个运行时额外暴露的全局变量。
不过需要注意,argv[0] 的内容取决于程序是如何被调用的,它可能是:
- 只有文件名
- 相对路径
- 完整路径
因此,argv[0] 更适合“获取启动时传入的程序标识”,不一定等同于“当前可执行文件的真实绝对路径”。
使用示例
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Program name: %sn", argv[0]);
return 0;
}
和 __progname 的区别
如果你只做类 Unix 平台开发,__progname 用起来更省事;如果你需要兼容 Windows,或者希望代码尽量通用,argv[0] 会更合适。
方法三:Linux 读取 /proc/self/exe 获取完整路径
如果你的目标不是“程序名”,而是“当前进程对应可执行文件的完整路径”,Linux 下常见做法是读取 /proc/self/exe 这个软链接。

它的原理是什么
/proc/self/exe 是一个指向当前进程可执行文件的符号链接。
/proc属于虚拟文件系统,用来提供进程和系统相关信息。self指向当前进程自身。- 如果当前 PID 是
1234,那么/proc/self/exe等价于/proc/1234/exe。
因此,读取这个链接,就能得到当前程序的执行路径。
使用示例
#include <stdio.h>
#include <unistd.h>
int main() {
char path[1024];
ssize_t len = readlink("/proc/self/exe", path, sizeof(path) - 1);
if (len != -1) {
path[len] = '\0'; // Null-terminate the string
printf("Executable path: %sn", path);
} else {
perror("readlink");
}
return 0;
}
使用时要注意
- 这个方法只能在 Linux 使用。
readlink不会自动补字符串结尾,所以示例里要手动写入'\0'。- 拿到的是完整路径,而不是单纯文件名。
方法四:Windows 使用 GetModuleFileName
在 Windows 平台,如果要获取当前可执行文件的完整路径,常用方式是调用 GetModuleFileName API。
它返回什么
GetModuleFileName 可以返回模块文件的完整路径。传入 NULL 时,表示获取当前进程主模块,也就是当前程序本身的路径。
使用示例
#include <windows.h>
#include <stdio.h>
int main() {
char path[MAX_PATH];
GetModuleFileName(NULL, path, MAX_PATH);
printf("Program path: %sn", path);
return 0;
}
适用场景
只要你的代码运行在 Windows,这基本就是最直接的方法。与 Linux 的 /proc/self/exe 类似,它解决的是“完整路径”问题,而不是简单文件名问题。
怎么选:4 种方法的适用范围一文看懂
| 方法 | 适用平台 | 获取结果 | 特点 |
|---|---|---|---|
__progname | 类 Unix | 通常是文件名 | 简单直接,但不跨平台 |
argv[0] | 类 Unix / Windows | 文件名、相对路径或完整路径 | 最通用,但结果依赖启动方式 |
/proc/self/exe | Linux | 完整路径 | 适合获取当前进程真实可执行文件路径 |
GetModuleFileName | Windows | 完整路径 | Windows 原生 API,适合系统级程序 |
简单归纳如下:
- 想写跨平台代码,优先看
argv[0]。 - 只在 Linux 或 macOS 上拿程序名,可以考虑
__progname。 - 只在 Linux 上拿真实执行路径,用
/proc/self/exe。 - 只在 Windows 上拿完整路径,用
GetModuleFileName。
番外:如何获取 C 运行时源码
如果你还想继续追到运行时实现层,比如查看相关变量或启动逻辑的来源,可以直接下载 glibc 源码。
通过包管理器下载
在 Debian/Ubuntu 系统中可以使用:
sudo apt-get source libc6
从官网下载压缩包
从 GitHub 镜像仓库获取
git clone https://github.com/bminor/glibc.git









