*Markus: (C) Implizite Deklaration der Funktion »strdup«

Hallo,

ich suchte nach einer simplen Methode, ein Verzeichnis auf Linux auszugeben. Dazu fand ich ein schönes Beispiel http://en.wikipedia.org/wiki/Dirent.h. In diesem Abschnitt....

  
while ((dp = readdir (dir)) != NULL) {  
        files[i] = strdup(dp->d_name);  
        if (files[i] == NULL) {  
            /* memory allocation failure; free what's been allocated  
             * so far and return NULL.  
             */  
            while (i > 0) {  
                free (files[--i]);  
            }  
            free (files);  
            return NULL;  
        }  
        printf ("%d: %s\n", i, dp->d_name);  
        i++;  
}  

scheint diese Zeile Warnungen beim Kompilieren auszulösen:

  
files[i] = strdup(dp->d_name);  

own_ls2.c:53: Warnung: Implizite Deklaration der Funktion »strdup«
own_ls2.c:53: Warnung: Zuweisung erzeugt Zeiger von Ganzzahl ohne Typkonvertierung

Die zweite Warnung bekomme ich weg, wenn ich eine Typumwandlung durchführe:

  
files[i] = (char *)strdup(dp->d_name);  

Aber ich bin mir nicht ganz sicher, wie ich mit der Warnung "own_ls2.c:53: Warnung: Implizite Deklaration der Funktion »strdup«" umgehen soll. Die Warnung sagt zwar schon alles, aber was bedeutet, dass strdup impilzit deklariert ist?

Danke,
Markus

  1. Moin.

    Aber ich bin mir nicht ganz sicher, wie ich mit der Warnung "own_ls2.c:53: Warnung: Implizite Deklaration der Funktion »strdup«" umgehen soll. Die Warnung sagt zwar schon alles, aber was bedeutet, dass strdup impilzit deklariert ist?

    Der Compiler bechwert sich, da strdup() nirgendwo deklariert wurde. Aus historischen Gründen nimmt er aber an, dass die Funktion eine Integer-Wert zurückliefert, d.h. eine nicht-deklarierten Funktion wird bei Verwendung implizit als int () deklariert.

    Um den Fehler zu beseitigen, binde den Header string.h ein, in dem die mit str... beginnenden Funktionen der Standardbibliothek zu finden sind.

    Christoph

    1. Hallo,

      Der Compiler bechwert sich, da strdup() nirgendwo deklariert wurde. Aus historischen Gründen nimmt er aber an, dass die Funktion eine Integer-Wert zurückliefert, d.h. eine nicht-deklarierten Funktion wird bei Verwendung implizit als int () deklariert.

      Um den Fehler zu beseitigen, binde den Header string.h ein, in dem die mit str... beginnenden Funktionen der Standardbibliothek zu finden sind.

      Das Seltsame ist, dass string.h aber eingebunden ist und die Warnung dennoch kommt. Also irgendwas muss da falsch laufen.

      Viele Grüße,
      Markus

      1. Übrigens, das Verhalten tritt nur dann auf, wenn ich mit -std=c99 kompiliere, hmmm?

        1. Moin.

          strdup() gehört nicht zur C99 Standardbibliothek, sondern ist Teil des POSIX-Standard.
          Deklariere die Funktion also selbst, d.h. füge an den Anfang deiner Quelldatei folgende Zeile ein:

          extern char * strdup(const char *);

          Alternativ könntest du auch im Modus -std=gnu99 kompilieren oder ganz auf strdup verzichten:

            
          size_t size = strlen(str) + 1;  
          char * copy = memcpy(malloc(size), str, size);  
          
          

          Christoph

      2. In diesem Zusammenhang habe ich noch ein Rätsel. Gebe ich mir zusätzlich die Fileinformationen aus, so funktioniert dies nur im aktuellen Verzeichnis. Übergebe ich als Parameter z.B ".." oder "/home/markus/", dann stimmen die Fileattribute wie Inode-Nummer etc nur von ".". Alle anderen Eigenschaft sind gleich. Ich habe "struct stat s;" sogar global definiert oder innerhalb der while-Schleife, aber dennoch bleibt die Information fälschlicherweise immer gleich. Meiner Meinung nach müsste die Übergabe durch dne Adressoperatur &s die Informationen bei jedem neuen File aktualisieren, aber das ist definitiv nicht so. Was ist da los? Ironischerweise stimmt aber der Inhalt von files[i]. Der Dateiname wird nämlich immer richtig ausgegeben. So gesehen liefert stat doch falsche Informationen zu dem übergebenen Dateinamen? Da das Ganze mit dme aktuellen Verzeichnis funktioniert, kann am Programm und an der Übergabe nichts falsch sein. Aber anscheinend macht mir die stat-Funktion einen Strich durch die Rechnung.

          
            while ((dp = readdir (dir)) != NULL) {  
                files[i] = (char *)strdup(dp->d_name);  
                if (files[i] == NULL) {  
                    /* memory allocation failure; free what's been allocated  
                     * so far and return NULL.  
                     */  
                    while (i > 0) {  
                        free (files[--i]);  
                    }  
                    free (files);  
                    return NULL;  
                }  
                printf("\n-----------------------------------------------------\n");  
                printf ("%d: %s\n", i, files[i]);  
        //Hier wird stat aufgerufen, um Infos aus den Files zu bekommen//  
                stat(files[i], &s);  
            	  printf("%-40s : %d\n", "Dateilaenge", s.st_size);  
            	  printf("%-40s : %ud\n", "Dateiattribute", s.st_mode);  
            	  printf("%-40s : %d\n", "Eigentümer", s.st_uid);  
            	  printf("%-40s : %d\n", "Gruppe", s.st_gid);  
            	  printf("%-40s : %d\n", "Inode-Nummer", s.st_ino);  
            	  printf("%-40s : %s", "Datum der letzten Modifikation", ctime(&s.st_mtime));  
            	  printf("%-40s : %s", "Datum der letzten Statusaenderung", ctime(&s.st_ctime));  
            	  printf("%-40s : %s", "Datum des letzten Lesezugriffs", ctime(&s.st_atime));  
          
                i++;  
            }  
          
            closedir (dir);  
            return files;  
        
        

        Markus

        1. Hallo,

          So gesehen liefert stat doch falsche Informationen zu dem übergebenen Dateinamen?

          Nein. dp->d_name enthält nur den Namen des Eintrages innerhalb des Verzeichnisses, nicht auch noch das Verzeichnis. Daher schlägt stat() bei allen Aufrufen fehl, außer die Datei existiert zufällig auch noch im aktuellen Verzeichnis, was nur bei '.' und '..' immer gegeben ist. Wenn stat() fehlschlägt (deswegen solltest Du Returncodes auch beachten!) ändert es den zweiten Parameter nicht und der enthält noch die alten Daten von vorher.

          Du müsstest den Verzeichnisnamen, '/' und den Eintrag konkatenieren, bevor Du ihn stat() übergibst. Und natürlich wie gesagt den Returncode von stat() überprüfen und wenn der fehlschlägt den dazugehörigen Fehlercode beachten, indem Du #include <errno.h> einbindest und dann im Fehlerfall die globale Variable [1] errno abfragst.

          [1] Genauer: Eigentlich ist das bei der glibc keine globale Variable sondern ein spezielles Makro was sich so verhält wie eine Variable (man kann errno etwas zuweisen und es auch auslesen), was aber für jeden Thread separat ist - damit ist das problemlos in mehreren Threads verwendbar.

          Viele Grüße,
          Christian

          --
          Mein "Weblog" [RSS]
          Using XSLT to create JSON output (Saxon-B 9.0 for Java)
          »I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«
                      -- Kommentar bei TDWTF
          1. Hallo,

            danke für die Info. Das klingt eigentlich plausibel und kann wirklich nur daran liegen. Ich werde es am Abend gleich ausprobieren.

            Viele Grüße,
            Markus

            P.S. Mittlerweile war auch einer meiner Arbeitskollegen der gleichen Meinung, dass es nur daran liegen kann.

            1. Hallo,

              alle Tipps haben geklappt, danke.

              Viele Grüße,
              Markus