2015-05-01 251 views
1

我想通过使用stat来检查给定的参数是否是目录。该程序需要2个参数:当第一个参数不是目录或它不存在代码工作正常。为什么stat会返回错误的结果?

但是,当第一个参数是一个目录并存在,并且第二个参数不存在时,程序会说它们都存在 - 错误的结果。我想知道为什么它不起作用。

#include <stdio.h> 
#include <sys/stat.h> 


int main(int n, char **argv) 
{ 
    char *dir_1=argv[1], *dir_2=argv[2]; 


    if (is_dir(dir_1) == 0) 
      printf("Directory %s exists.\n", dir_1); 
    else 
      printf("Directory %s does not exist.\n", dir_1); 

    if (is_dir(dir_2) == 0) 
      printf("Directory %s exists.\n", dir_2); 
    else 
      printf("Directory %s does not exist.\n", dir_2); 

} 


int is_dir(char *file) 
{ 
     struct stat file_stat; 
     stat(file, &file_stat); 
     return((S_ISDIR(file_stat.st_mode)) ? 0 : -1); 
} 
+1

由于使用功能的前*预计*输出,你应该检查它的返回值,看看它是否曾在所有。 –

+0

如果函数只被调用一次,那么它总是正常工作。但是当我调用它两次时,它在所有情况下都不会返回预期值。 – user3140972

+1

您没有'is_dir'的函数原型,所以编译器假定您传递了一个'int'参数。也许这就是为什么它行事不端。启用并记下所有编译器警告。 –

回答

4

如果文件不存在,stat自己返回-1,并设置errnoENOENT。但是由于第一个目录存在并且是一个目录,所以struct stat填充了一个目录的信息;这恰好位于堆栈中第二个调用的完全相同的位置。第二个staterrnoENOENT失败,但随后is_dir解释了第一个调用留下的值。


is_dir更正确的实现可以是:

int is_dir(char *file) 
{ 
    struct stat file_stat; 

    // if an error occurs, we return 0 for false 
    if (stat(file, &file_stat) < 0) { 
     return 0; 
    } 

    // otherwise we return whatever the S_ISDIR returns 
    return S_ISDIR(file_stat.st_mode); 
} 

请注意,我改变返回值太大;一个函数如is_dir预计会返回一个布尔值,在函数名称为true事实的情况下,该值为非零(非零),否则返回零。

你会使用它像:

if (is_dir(dir_1)) { 
     printf("Directory %s exists.\n", dir_1); 
} 
else { 
     printf("Directory %s does not exist.\n", dir_1); 
} 

if (is_dir(dir_2)) { 
     printf("Directory %s exists.\n", dir_2); 
} 
else { 
     printf("Directory %s does not exist.\n", dir_2); 
} 

注意,在这种情况下,返回值为0,并不意味着必然存在与该名称的目录;系统调用stat也可能因为权限不足等原因而失败;扩展逻辑(解释价值errno)超出了这个答案的范围。

+0

或者,可以将其重命名为test_dir。 – user3125367

+0

优雅的解决方案。我喜欢阅读漂亮的C代码。 –

+0

谢谢,这回答我的问题。我只是想知道为什么当第二个目录不存在时返回0。我认为'struct stat'被初始化为一些值。 – user3140972

1

这个答案在另一个被接受之后。在MSVC中不存在S_ISDIR,而是存在_S_IFDIR。替换之后,编译器通知is_dir()未返回值。原因是,_S_IFDIR是一个掩码,而不是一个函数。所以在对代码进行一些调整之后,我得到了这个工作。

#include <stdio.h> 
#include <sys/stat.h> 

int is_dir(char *file) 
{ 
    struct stat file_stat; 
    if (stat(file, &file_stat) == 0)     // check it worked 
     return file_stat.st_mode & _S_IFDIR;   // it's a status mask 
    return 0; 
} 

int main(int argc, char **argv)       // conventional ids 
{ 
    char *dir_1, *dir_2; 
    if (argc < 3) return 0;        // check silliness 
    dir_1=argv[1]; 
    dir_2=argv[2]; 

    if (is_dir(dir_1))         // reversed the logic 
     printf("%s is a Directory.\n", dir_1); 
    else 
     printf("%s is not a Directory.\n", dir_1);  // better text 

    if (is_dir(dir_2)) 
     printf("%s is a Directory.\n", dir_2); 
    else 
     printf("%s is not a Directory.\n", dir_2); 
    return 0; 
} 

程序输出:

>test test.c wtest 
test.c is not a Directory. 
wtest is a Directory. 

而且反过来:

>test wtest test.c 
wtest is a Directory. 
test.c is not a Directory. 
+0

谢谢。这是一个需要跨平台的项目的一小部分。所以'_S_IFDIR'会很有用。 – user3140972

相关问题