S_IFMT и S_IFREG не определены с -std=c11 или -std=gnu11

Я впервые работаю с 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 */
}

Но используя GCC 4.8.3 в Gentoo, если я скомпилировал с -std=c99 или -std=c11 или -std=gnu99 или -std=gnu11, я получил эту ошибку:

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

Если я опускаю -std=*, я не получаю ошибок. Но мне также нужны все возможности -std=c99 (например, ключевое слово limited или for(int i;;) и т. д.). Как мне скомпилировать свой код?


person Giorgio Napolitano    schedule 16.02.2015    source источник
comment
Это немного странно. Не могли бы вы создать минимальный автономный пример, чтобы я мог воспроизвести эту проблему в своей системе? Я не мог воспроизвести это иначе.   -  person fuz    schedule 21.02.2015


Ответы (3)


Современные POSIX-совместимые системы должны предоставлять значения S_IFMT и S_IFREG. Единственная версия POSIX, которая этого не требует (и фактически запрещает), — это POSIX.1-1990, которая является стандартом для вашей машины.

В любом случае каждая POSIX-совместимая система предоставляет макросы, которые позволяют проверить тип файла. Эти макросы эквивалентны методу маскирования.

Так что в вашем случае вместо (sb.st_mode & S_IFMT) == S_IFREG просто напишите S_ISREG(sb.st_mode).

person Daniel Kleinstein    schedule 16.02.2015
comment
Это не отвечает на вопрос, что __S_IFMT и __S_IFREG являются внутренними константами, которые никогда не должны использоваться пользовательской программой. Кроме того, OP спрашивает о POSIX, и вы даете неответ на конкретную платформу. - person fuz; 21.02.2015
comment
@FUZxxl Первая часть моего ответа действительно отвечает на вопрос, вторая часть моего ответа предназначена только для случая, когда OP действительно (и излишне) настаивает на маскировке самостоятельно. - person Daniel Kleinstein; 21.02.2015
comment
@FUZxxl OP также может принимать числовые значения внутренних констант и просто использовать их в своей программе, но это просто не нужно, потому что системные макросы POSIX делают маскировку за вас (как объяснено в моем ответе, не зависящем от платформы). - person Daniel Kleinstein; 21.02.2015
comment
Но вы можете сделать маскировку самостоятельно с помощью POSIX! POSIX явно указывает, что маскирование с помощью S_IFMT и последующее сравнение должны работать. Для этого не нужны никакие внутренние макросы. - person fuz; 21.02.2015
comment
@FUZxxl В стандарте не указано, что S_IFMT и S_IFREG должны предоставляться пользовательским программам. Он может работать при компиляции под -std=c99 на вашем компьютере, но на моем компьютере и компьютере OP это не работает, и он не должен должен работать, потому что макросы POSIX делают ненужным предоставление S_IFMT и S_IFREG пользовательским программам. . Ваш минус необоснован. - person Daniel Kleinstein; 21.02.2015
comment
Да, применяется (для систем, совместимых с XSI). Эта ссылка содержит все, что должно быть в sys/stat.h, включая S_IFMT и S_IFREG. Пожалуйста, прекратите распространять дезинформацию. - person fuz; 21.02.2015
comment
В будущих направлениях даже не сказано, что этот материал будет удален. Интересно, что они, кажется, не говорят явно, что могут маскировать mode_t с S_IFMT, а затем сравнивать с одной из представленных там констант, но это как бы подразумевается тем, как работают эти макросы. Позвольте мне подтвердить с коллегой, который находится на PASC. - person fuz; 21.02.2015
comment
@FUZxxl POSIX 2008 действительно требует описания значения S_IFMT. Однако POSIX.1-1990 этого не делает — фактически он требует использования макроса S_IFREG. Машины Mine и OP, по-видимому, совместимы с POSIX.1-1990. Я отредактировал свой ответ соответствующим образом, спасибо, что поправили меня. - person Daniel Kleinstein; 21.02.2015
comment
Последние выпуски glibc в основном совместимы с POSIX 2008. Они должны фактически раскрыть эти макросы. Вот почему мне интересно. - person fuz; 21.02.2015
comment
Извините, ссылка, idk, мертва? Не могли бы вы обновить информацию? Было бы полезно. - person LRDPRDX; 02.02.2020

Поместите #define _BSD_SOURCE или #define _XOPEN_SOURCE перед любым #include в исходном коде. Чтобы понять, почему это работает, посмотрите прямо над #define S_IFMT __S_IFMT в sys/stat.h, а затем на справочной странице feature_test_macros(7).

person Peter968475    schedule 23.02.2015

K&R2 предоставляет:

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

в главе 8.6 Каталоги с примерами.

Я НЕ призываю использовать это решение, более того, я надеюсь, что некоторые эксперты могут научить нас, правильно оно реализовано или нет, плюсы-минусы, альтернативы и так далее. Спасибо заранее!

Пример МВЕ.

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;
}
person Xopi García    schedule 31.12.2018
comment
Эм... Чтобы быть точным, в K&R2 написано [...] Определения флагов также включены в <sys/stat.h>[...]. - person LRDPRDX; 02.02.2020