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

实现ls -aln功能的C程序输出异常,请求排查修复

问题描述

我写了一个实现ls -aln命令功能的C程序,但出了问题。

预期输出

drwxr-xr-x@  6 seven  staff   192 19 fév 18:58 .
drwxr-xr-x@  4 seven  staff   128  6 fév 00:37 ..
drwxr-xr-x@  7 seven  staff   224 17 fév 15:00 .idea
-rw-r--r--@  1 seven  staff   104  5 fév 17:37 CMakeLists.txt
drwxr-xr-x@ 11 seven  staff   352 19 fév 18:58 cmake-build-debug
-rw-r--r--@  1 seven  staff  2144 19 fév 18:58 main.c

实际输出

d-----rwxr-xr-x  11  352     seven   staff   .
d-----rwxr-xr-x  6   192     seven   staff   ..
d-----rwxr-xr-x  6   192     seven   staff   cmake-build-debug
d-----rwxr-xr-x  6   192     seven   staff   CMakeLists.txt
d-----rwxr-xr-x  6   192     seven   staff   main.c
d-----rwxr-xr-x  6   192     seven   staff   .idea

问题表现

  • 链接数不符合预期
  • 文件大小不正确
  • 权限显示异常(所有文件都被标记为目录,且权限位前多了多余的-----)
  • 缺少文件修改时间字段

我怀疑是printf的问题,但不知道怎么修复,以下是我的代码:

int main() {
    char* curr_dir = NULL;
    DIR* dir = NULL;
    struct dirent* entity = NULL;
    struct stat fileStat;
    struct passwd* pwd;
    struct group* gid;

    curr_dir = getenv("PWD");//current directory with PWD
    if (curr_dir==NULL){
        printf("ERROR: j'ai pas pris le repertoire courrant");
    }


    dir = opendir("/Users/seven/Desktop/Programmazione/TP");
    if(dir == NULL) {
        printf("ERROR: j'ai pas pue ouvrir le repertoire");
    }

    while((entity = readdir(dir)) != NULL){
        stat(entity->d_name, &fileStat);
        printf((S_ISDIR(fileStat.st_mode)) ? "d" : "-");
        printf((S_ISLNK(fileStat.st_mode)) ? "l" : "-");
        printf((S_ISSOCK(fileStat.st_mode)) ? "s" : "-");
        printf((S_ISFIFO(fileStat.st_mode)) ? "p" : "-");
        printf((S_ISBLK(fileStat.st_mode)) ? "b" : "-");
        printf((S_ISCHR(fileStat.st_mode)) ? "c" : "-");
        printf((fileStat.st_mode & S_IRUSR) ? "r" : "-");
        printf((fileStat.st_mode & S_IWUSR) ? "w" : "-");
        printf((fileStat.st_mode & S_IXUSR) ? "x" : "-");
        printf((fileStat.st_mode & S_IRGRP) ? "r" : "-");
        printf((fileStat.st_mode & S_IWGRP) ? "w" : "-");
        printf((fileStat.st_mode & S_IXGRP) ? "x" : "-");
        printf((fileStat.st_mode & S_IROTH) ? "r" : "-");
        printf((fileStat.st_mode & S_IWOTH) ? "w" : "-");
        printf((fileStat.st_mode & S_IXOTH) ? "x" : "-");
        printf("\t %u", fileStat.st_nlink);
        printf("\t %lld", fileStat.st_size);
        pwd = getpwuid(fileStat.st_uid);
        gid = getgrgid(fileStat.st_gid);
        if(pwd != NULL && gid != NULL ){
            printf("\t %s", pwd->pw_name);
            printf("\t %s", gid->gr_name);
        }
        printf("\t %s\n", entity->d_name);

    }

    closedir(dir);
} 

问题分析与修复

1. 文件类型判断逻辑错误

当前代码会把所有文件类型的判断结果都输出一遍(不满足就输出-),导致权限位前多了5个多余的-。正确逻辑是只输出一个对应文件类型的字符:

// 仅输出一个文件类型标识
if (S_ISDIR(fileStat.st_mode)) printf("d");
else if (S_ISLNK(fileStat.st_mode)) printf("l");
else if (S_ISSOCK(fileStat.st_mode)) printf("s");
else if (S_ISFIFO(fileStat.st_mode)) printf("p");
else if (S_ISBLK(fileStat.st_mode)) printf("b");
else if (S_ISCHR(fileStat.st_mode)) printf("c");
else printf("-");

2. stat调用未使用完整路径,导致属性读取错误

你打开的是指定目录,但调用stat时只用了文件名,若程序当前工作目录不是目标目录,stat会找不到文件,导致fileStat保留上一次的旧数据,这就是所有文件属性重复的原因。解决方法是拼接完整路径:

char full_path[PATH_MAX];
snprintf(full_path, sizeof(full_path), "%s/%s", "/Users/seven/Desktop/Programmazione/TP", entity->d_name);
if (stat(full_path, &fileStat) == -1) {
    perror("stat failed");
    continue;
}

3. 输出格式未对齐,缺少时间字段

ls -aln用固定宽度对齐输出,\t会导致排版混乱;同时代码未输出文件修改时间,需用strftime格式化st_mtime。

4. 变量类型匹配问题

st_nlink类型是nlink_t,st_size是off_t,需用对应格式符避免输出错误,比如%4u、%8lld。

修正后的完整代码

#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <limits.h>

int main() {
    const char* target_dir = "/Users/seven/Desktop/Programmazione/TP";
    DIR* dir = opendir(target_dir);
    if (dir == NULL) {
        perror("Failed to open directory");
        return 1;
    }

    struct dirent* entity;
    struct stat fileStat;
    struct passwd* pwd;
    struct group* gid;
    char full_path[PATH_MAX];
    char time_buf[64];

    while ((entity = readdir(dir)) != NULL) {
        // 拼接完整文件路径
        snprintf(full_path, sizeof(full_path), "%s/%s", target_dir, entity->d_name);
        if (stat(full_path, &fileStat) == -1) {
            fprintf(stderr, "stat %s failed: %s\n", entity->d_name, strerror(errno));
            continue;
        }

        // 输出文件类型
        if (S_ISDIR(fileStat.st_mode)) printf("d");
        else if (S_ISLNK(fileStat.st_mode)) printf("l");
        else if (S_ISSOCK(fileStat.st_mode)) printf("s");
        else if (S_ISFIFO(fileStat.st_mode)) printf("p");
        else if (S_ISBLK(fileStat.st_mode)) printf("b");
        else if (S_ISCHR(fileStat.st_mode)) printf("c");
        else printf("-");

        // 输出权限位
        printf((fileStat.st_mode & S_IRUSR) ? "r" : "-");
        printf((fileStat.st_mode & S_IWUSR) ? "w" : "-");
        printf((fileStat.st_mode & S_IXUSR) ? "x" : "-");
        printf((fileStat.st_mode & S_IRGRP) ? "r" : "-");
        printf((fileStat.st_mode & S_IWGRP) ? "w" : "-");
        printf((fileStat.st_mode & S_IXGRP) ? "x" : "-");
        printf((fileStat.st_mode & S_IROTH) ? "r" : "-");
        printf((fileStat.st_mode & S_IWOTH) ? "w" : "-");
        printf((fileStat.st_mode & S_IXOTH) ? "x" : "-");

        // 输出macOS扩展属性标记@
        struct statfs fs_stat;
        if (statfs(full_path, &fs_stat) == 0 && (fs_stat.f_flags & MNT_DONTBROWSE)) {
            printf("@");
        } else {
            printf(" ");
        }

        // 输出链接数、用户/组名、文件大小
        printf(" %4u ", fileStat.st_nlink);
        pwd = getpwuid(fileStat.st_uid);
        gid = getgrgid(fileStat.st_gid);
        printf("%-8s %-8s ", pwd ? pwd->pw_name : "unknown", gid ? gid->gr_name : "unknown");
        printf("%8lld ", (long long)fileStat.st_size);

        // 输出格式化后的修改时间
        strftime(time_buf, sizeof(time_buf), "%d %b %H:%M", localtime(&fileStat.st_mtime));
        printf("%s ", time_buf);

        // 输出文件名
        printf("%s\n", entity->d_name);
    }

    closedir(dir);
    return 0;
}

修复效果说明

  • 修正文件类型判断,移除多余的-----
  • 使用完整路径调用stat,获取正确的文件属性
  • 固定宽度格式化输出,对齐方式与ls -aln一致
  • 添加文件修改时间输出
  • 处理stat调用失败的异常情况

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 10:55:51