在使用-std=c11或-std=gnu11时,S_IFMT和S_IFREG未定义。

7

这是我第一次使用posix;我已经包含了:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

我有一个代码片段。

而且我有这个片段。

stat(pathname, &sb);
if ((sb.st_mode & S_IFMT) == S_IFREG) {
    /* Handle regular file */
}

但是,在 Gentoo 上使用 GCC 4.8.3 编译时,如果我使用 -std=c99、-std=c11 或 -std=gnu99、-std=gnu11 这些选项进行编译,就会出现以下错误:

error: ‘S_ISFMT’ undeclared (first use in this function)

如果我省略 -std=*,就不会出现错误。但我也想要 -std=c99 的所有功能(如关键字 restrict 或 for(int i;;) 等等...)。我该如何编译我的代码?

这有点奇怪。你能否构建一个最小的自包含示例,以便我可以在我的系统上重现此问题?否则我无法复现它。 - fuz
3个回答

6
现代的POSIX兼容系统需要提供S_IFMTS_IFREG值。唯一不需要(事实上,禁止)这样做的POSIX版本是POSIX.1-1990,它似乎是您的计算机上的标准。
无论如何,每个符合POSIX标准的系统都提供,让您可以检查文件的类型。这些宏等效于掩码方法。
因此,在您的情况下,只需编写S_ISREG(sb.st_mode),而不是(sb.st_mode&S_IFMT)== S_IFREG

这并没有回答问题。__S_IFMT__S_IFREG是内部常量,不应该被用户程序使用。此外,OP问的是POSIX相关的问题,而你给出了一个特定于平台的非答案。 - fuz
@FUZxxl 我的回答的第一部分确实回答了问题,第二部分只是针对 OP 非常(而且不必要)坚持自己进行掩码处理的情况。 - Daniel Kleinstein
@FUZxxl OP也可以在程序中使用内部常量的数值,但这是不必要的,因为POSIX系统宏会为您执行掩码操作(如我在非平台特定答案中所解释的)。 - Daniel Kleinstein
@FUZxxl POSIX 2008确实需要描述S_IFMT值。然而,POSIX.1-1990并没有要求 - 实际上它要求使用S_IFREG宏。我和OP的机器显然符合POSIX.1-1990标准。我已经相应地编辑了我的答案,感谢您的纠正。 - Daniel Kleinstein
最近的glibc版本大多数都符合POSIX 2008标准。它们应该实际上暴露这些宏。这就是我为什么感到疑惑的原因。 - fuz
显示剩余5条评论

4

在您的源代码中的任何#include之前,将#define _BSD_SOURCE#define _XOPEN_SOURCE放置在。要了解为什么这样做有效,请查看sys/stat.h#define S_IFMT __S_IFMT正上方,然后查看feature_test_macros(7)手册页面。


2

《C程序设计语言(第2版)》提供了:

#define S_IFMT 0160000 /* type of file: */
#define S_IFDIR 0040000 /* directory */

在第8.6章节中,列出了目录的示例。

我不鼓励使用这个解决方案,而且我希望一些专家能够教给我们它是否正确实现、优缺点、替代方案等。提前感谢!

下面是MWE示例。

MWE示例:

/* these defines at beginning to highlight them */
#define S_IFMT 0160000 /* type of file: */
#define S_IFDIR 0040000 /* directory */

/*
   Modify the fsize program to print the other information contained in the inode entry.
   */

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <dirent.h>
#include <pwd.h>


#define MAX_PATH 1024

#ifndef DIRSIZ
#define DIRSIZ 14
#endif


void dirwalk( char *dir,void (*fcn)(char *)){

    char name[MAX_PATH];
    struct dirent *dp;
    DIR *dfd;

    if((dfd = opendir(dir))==NULL){
        puts("Error: Cannot open Directory");
        return;
    }
    puts(dir);
    // Get each dir entry
    while((dp=readdir(dfd)) != NULL){
        // Skip . and .. is redundant.
        if(strcmp(dp->d_name,".") == 0
            || strcmp(dp->d_name,"..") ==0 )
            continue;
        if(strlen(dir)+strlen(dp->d_name)+2 > sizeof(name))
            puts("Error: Name too long!");
        else{
            sprintf(name,"%s/%s",dir,dp->d_name);
            // Call fsize
            (*fcn)(name);
        }
    }
    closedir(dfd);
}

void fsize(char *name){
    struct stat stbuf;

    if(stat(name,&stbuf) == -1){
        puts("Error: Cannot get file stats!");
        return;
    }

    if((stbuf.st_mode & S_IFMT) == S_IFDIR){
        dirwalk(name,fsize);
    }
    struct passwd *pwd = getpwuid(stbuf.st_uid);
    //print file name,size and owner
    printf("%81d %s Owner: %s\n",(int)stbuf.st_size,name,pwd->pw_name);
}

int main(int argc,char *argv[]){

    if(argc==1)
        fsize(".");
    else 
        while(--argc>0)
            fsize(*++argv);
    return 0;
}

嗯……确切地说,在K&R2中写道:“[...]标志定义也包含在<sys/stat.h>中[...]”。 - LRDPRDX

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接