一尘不染

pure C:使用fopen()打开目录

linux

我有一个程序来打开文件并检查其长度。

FILE* fd = fopen(argv[1], "rb");
fseek(fd, 0, SEEK_END);
size_t flen = ftell(fd);
if (flen == ((size_t)-1)) {
    printf("%s is a directory.\n", argv[1]);
    fclose(fd);
    exit(1);
}

现在,至少在Linux下,fopen()打开目录时会返回有效的文件描述符。这导致查找操作返回-1(或者,如size_t无符号,在64位系统上为0xFFFFFFFFFFFFFFFF=
2 64 -1)。

不幸的是,上面的代码(flen == ((size_t)-1))中的条件无法解决这种情况,flen == 0xFFFFFFFF(EDIT:应该是0xFFFFFFFFFFFFFFFF)也没有。printf()-将%xord
%d作为格式字符串的命令显示比较的两面应具有相同的值。

为什么即使两边都是相同类型(size_t),比较运算符的行为也是如此奇怪?我正在使用gcc 4.8.1作为编译器。


阅读 349

收藏
2020-06-02

共1个答案

一尘不染

目录在C99标准(或C2011标准)中不存在。因此,根据定义,fopen-ing目录是实现特定的行为或未定义的行为。

fopen(3)可能会失败(给出NULL结果)。fseek(3)也可能失败(返回-1)。然后您最好检查errno(3)或使用perror(3)

ftell是记录在案,以返回long,和-1L失败。在64位Linux上,这是0xffffffffffffffff

您的代码应改为

FILE* fd = fopen(argv[1], "rb");
if (!fd) 
  { perror(argv[1]); exit(EXIT_FAILURE); };
if (fseek(fd, 0, SEEK_END)<0) 
  { perror("fseek"); exit(EXIT_FAILURE); };
long flen = ftell(fd);
if (flen == -1L)
  { perror("ftell"); exit(EXIT_FAILURE); };

顺便说一句,在具有libc-2.17和3.10.6内核的Linux / Debian / Sid / AMD64上,当argv[1]is
时,代码可以正常运行/tmp;惊喜地,flenLONG_MAX0x7fffffffffffffff

顺便说一句,在Linux上,目录是文件的特例。在文件路径上(以及在文件描述符(可能是通过some从fileno(3)获取使用stat(2)来了解有关某个文件的更多元数据,包括其“类型”(通过其模式)。您希望opendir(3)readdir(3)closedir(3)对目录内容进行操作。另请参见inode(7)fstatFILE*

2020-06-02