You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

用C代码读取/proc获取有效PID输出异常,求代码排查

问题分析与代码修正

你的代码存在几个关键错误,导致输出大量无效PID:

1. 未定义PROC_PATH宏

代码中直接使用PROC_PATH但未通过#define定义,编译时该宏会被视为空字符串。此时拼接出的路径是纯数字(如"123"),实际打开的是当前工作目录下的数字命名目录,而非/proc/[PID],这是输出大量无效结果的核心原因。

2. 文件描述符泄漏

每次open成功后未调用close(fd)释放文件描述符,当循环次数过多时,系统可用文件描述符会被耗尽,后续open调用全部失败,无法正确检测PID。

3. 遍历范围不合理

Linux系统的PID最大值默认由/proc/sys/kernel/pid_max决定(通常为32768或65535),遍历到99999会执行大量无用循环。

修正后的代码(不依赖进程相关内置结构体)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

#define PATH_LINE 128
#define PROC_PATH "/proc/"

void get_pid() {
    char full_path[PATH_LINE];
    int fd;
    struct stat st;
    int max_pid = 65535; // 默认最大PID值

    // 读取系统实际最大PID,减少无效遍历
    FILE *pid_max_file = fopen("/proc/sys/kernel/pid_max", "r");
    if (pid_max_file) {
        fscanf(pid_max_file, "%d", &max_pid);
        fclose(pid_max_file);
    }

    for (int i = 0; i < max_pid; i++) {
        memset(full_path, 0, PATH_LINE);
        // 用snprintf安全拼接路径,避免缓冲区溢出
        snprintf(full_path, PATH_LINE, "%s%d", PROC_PATH, i);

        fd = open(full_path, O_RDONLY);
        if (fd != -1) {
            // 验证打开的是目录(确保是有效进程PID目录)
            if (fstat(fd, &st) == 0 && S_ISDIR(st.st_mode)) {
                printf("%d\n", i); // 直接输出PID即可,无需打印路径
            }
            close(fd); // 立即释放文件描述符
        }
    }
}

int main(void) {
    get_pid();
    return 0;
}

修正说明

  • 明确定义PROC_PATH为"/proc/",确保路径拼接正确指向/proc下的PID目录。
  • 使用snprintf替代strcat+sprintf,避免缓冲区溢出风险。
  • 读取/proc/sys/kernel/pid_max获取系统实际最大PID,减少无用循环。
  • 添加fstat验证打开的是目录,排除非进程的数字命名条目(Linux下/proc的数字条目几乎都是进程目录,该验证让逻辑更严谨)。
  • 每次open成功后立即调用close(fd),避免文件描述符泄漏。

内容的提问来源于stack exchange,提问作者Tal Roz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 08:15:28