C 获取程序名称的 4 种方法:`__progname`、`argv[0]`、`/proc/self/exe` 与 `GetModuleFileName`

沈亦白
沈亦白
发布时间:2026-08-24 | 154人浏览过
原创

前言

在 C 里获取当前程序名,很多人第一反应是直接读一个变量或参数,但真正写到跨平台代码时,很快就会遇到“这到底是文件名、启动参数,还是可执行文件完整路径”的区别。本文按平台和目标拆开说明 4 种常见做法,既保留原始示例,也把各自的限制条件和适用场景讲清楚,方便你在 Linux、macOS、Windows 场景下快速判断。

在 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 这个软链接。

Linux 通过 /proc/self/exe 获取当前可执行文件路径的原理信息图
`/proc/self/exe` 背后的路径这一方式的关键不是 API 名字,而是理解 `/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/exeLinux完整路径适合获取当前进程真实可执行文件路径
GetModuleFileNameWindows完整路径Windows 原生 API,适合系统级程序

简单归纳如下:

  • 想写跨平台代码,优先看 argv[0]。
  • 只在 Linux 或 macOS 上拿程序名,可以考虑 __progname。
  • 只在 Linux 上拿真实执行路径,用 /proc/self/exe。
  • 只在 Windows 上拿完整路径,用 GetModuleFileName。

番外:如何获取 C 运行时源码

如果你还想继续追到运行时实现层,比如查看相关变量或启动逻辑的来源,可以直接下载 glibc 源码。

通过包管理器下载

在 Debian/Ubuntu 系统中可以使用:

sudo apt-get source libc6

从官网下载压缩包

www.gnu.org/software/li…

从 GitHub 镜像仓库获取

git clone https://github.com/bminor/glibc.git

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表