2015-05-01 92 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