2010-02-04 16 views
24

Ich sehe C des getcwd über: Mann 3 cwdGibt es ein C++ - Äquivalent zu getcwd?

Ich vermute, C++ ein ähnliches hat, zurückgeben, könnten Sie mir eine std :: string.

Wenn ja, wie heißt es, und wo finde ich die Dokumentation?

Danke!

+4

Warum nicht einfach 'std :: string cwd = getcwd();' verwenden und der Konstruktor seine Arbeit machen lassen? – LiraNuna

+0

wird das Speicherleck nicht? – anon

+4

Leckt getcwd() Speicher, wenn Sie es nicht freigeben? Wenn dies der Fall ist, sollten Sie es nach dem Erstellen der Zeichenfolge freigeben, anstatt es freizugeben, wenn Sie es nicht mehr benötigen, und das ist bequemer. Wenn nicht, wird der Speicher bei der Initialisierung der Zeichenfolge nicht gelöscht. –

Antwort

20

Ok, ich antworte, obwohl Sie bereits eine Antwort angenommen haben.

Ein noch besserer Weg als den getcwd Aufruf zu wickeln wäre boost::filesystem, wo Sie ein path Objekt aus der current_path() Funktion erhalten. Die Boost-Dateisystem-Bibliothek ermöglicht es Ihnen, viele andere nützliche Dinge zu tun, die Sie sonst viel String-Parsing tun müssten, wie das Überprüfen, ob Dateien/Verzeichnisse vorhanden sind, den übergeordneten Pfad, Pfade vervollständigen und so weiter. Überprüfen Sie es, es ist auch portabel - was eine Menge der String-Parsing-Code würde sonst wahrscheinlich verwenden würde nicht sein.

Update (2016): Dateisystem wurde 2015 als technical specification veröffentlicht, basierend auf Boost Dateisystem v3. Dies bedeutet, dass es möglicherweise bereits mit Ihrem Compiler verfügbar ist (z. B. Visual Studio 2015). Mir erscheint es auch wahrscheinlich, dass es Teil eines zukünftigen C++ - Standards wird (ich würde C++ 17 annehmen, aber ich bin mir des aktuellen Status nicht bewusst).

Update (2017): Die filesystem library wurde mit ISO C++ in C++ 17 fusionierte für

std::filesystem::current_path(); 
+1

Natürlich lohnt es sich in einigen Situationen nicht, die boost :: Dateisystem-Bibliothek einzubinden, nur um das aktuelle Arbeitsverzeichnis zu erhalten. Allerdings, wenn er viele Dateisystem-Sachen macht, dann können sie auch Boost für alles verwenden. –

+7

Warum ist jede Antwort boost :: this boost :: that? – TheRealChx101

+0

@ chx101: Ich denke Boost ist nicht immer die Antwort. Aber in einigen Fällen ist es das, und etwas zu verwenden, das bereits existiert und dein Leben leichter macht, ist normalerweise eine gute Sache. Beachten Sie, dass einige Dinge, die jetzt im C++ - Standard sind, von Boost stammen und dass Boost-Dateisystem für die Aufnahme als technische Spezifikation vorgesehen ist. – villintehaspam

17

std::string 's Konstruktor kann sicher eine char* als Parameter nehmen. Überraschenderweise gibt es auch eine windows version.

Edit: eigentlich ist es ein wenig komplizierter:

std::string get_working_path() 
{ 
    char temp[MAXPATHLEN]; 
    return (getcwd(temp, MAXPATHLEN) ? std::string(temp) : std::string("")); 
} 

Speicher ist kein Problem - Temp ein Stapel basierten Puffer ist, und die std :: string Konstruktor hat eine Kopie. Wahrscheinlich könntest du es auf einmal machen, aber ich denke nicht, dass der Standard das garantieren würde.

über Speicherzuordnung, über POSIX:

Die getcwd() Funktion einen absoluten Pfadnamen des aktuellen Arbeitsverzeichnisses in dem Feld platzieren soll, auf den buf und buf zurück. Der Pfadname in das Array kopiert darf keine Komponenten enthalten, die symbolische Links sind. Das Argument Größe ist die Größe des Zeichenarrays, auf das das Argument buf verweist, in Byte. Wenn buf ein Nullzeiger ist, ist das Verhalten von getcwd() nicht spezifiziert.

+2

Sowohl diese Antwort als auch Liranunas Kommentar verwenden 'getcwd' als keine Argumentfunktion, aber die Dokumentation, die ich sehe, zeigt zwei Parameter. Liest ich die falschen Dokumente? –

+2

ist das char * automatisch freigegeben? oder gibt mir das ein Speicherleck? – anon

+0

@anon nein, das resultierende char * ist "malloc" ed und sollte nach dem Erstellen einer std :: string "frei" sein. – Bill

3

Alle C-Funktionen sind auch C++ - Funktionen. Wenn Sie eine std::string benötigen, erstellen Sie einfach eine aus der char*, die getcwd für Sie bekommt.

4

Sie müssen nur einen kleinen Wrapper schreiben.

std::string getcwd_string(void) { 
    char buff[PATH_MAX]; 
    getcwd(buff, PATH_MAX); 
    std::string cwd(buff); 
    return cwd; 
} 
+0

Sie sollten PATH_MAX anstelle einer magischen Zahl verwenden. – Bill

+0

@Bill danke, lerne jeden Tag etwas Neues. –

+0

Ausgezeichnet, danke! –

11

Lassen Sie uns versuchen und schreiben diese einfache C-Aufruf als C++:

std::string get_working_path() 
{ 
    char temp [ PATH_MAX ]; 

    if (getcwd(temp, PATH_MAX) != 0) 
     return std::string (temp); 

    int error = errno; 

    switch (error) { 
     // EINVAL can't happen - size argument > 0 

     // PATH_MAX includes the terminating nul, 
     // so ERANGE should not be returned 

     case EACCES: 
      throw std::runtime_error("Access denied"); 

     case ENOMEM: 
      // I'm not sure whether this can happen or not 
      throw std::runtime_error("Insufficient storage"); 

     default: { 
      std::ostringstream str; 
      str << "Unrecognised error" << error; 
      throw std::runtime_error(str.str()); 
     } 
    } 
} 

Die Sache ist, wenn Sie eine Bibliotheksfunktion in eine andere Funktion einfügen, müssen Sie davon ausgehen, dass alle Funktionen verfügbar gemacht werden sollten, da eine Bibliothek nicht weiß, was sie aufrufen wird. Sie müssen also die Fehler behandeln, anstatt sie nur zu verschlucken oder zu hoffen, dass sie nicht passieren.

Es ist normalerweise besser, den Client-Code nur die Bibliotheksfunktion aufrufen zu lassen und den Fehler zu diesem Zeitpunkt zu behandeln - der Client-Code interessiert wahrscheinlich nicht, warum der Fehler aufgetreten ist, und muss nur das Pass/Fail-Verhalten behandeln und nicht alle Fehlercodes.

+1

Es gibt einen Tippfehler. Es sollte '! = 0' statt' == 0' in der fünften Zeile sein. – Phantrast

2

verwendete ich getcwd() in C auf folgende Weise:

char * cwd; 
cwd = (char*) malloc(FILENAME_MAX * sizeof(char)); 
getcwd(cwd,FILENAME_MAX); 

Die Header-Datei benötigt stdio.h ist. Wenn ich C-Compiler verwende, funktioniert es perfekt.

Wenn ich kompilieren genau den gleichen Code unter Verwendung von C++ Compiler, es gibt die folgende Fehlermeldung:

identifier "getcwd" is undefined 

Dann I der unistd.h und mit C++ Compiler kompiliert. Diesmal funktioniert alles. Als ich zurück zum C-Compiler wechselte, funktioniert es immer noch!

Solange Sie beide stdio.h und unistd.h enthalten, funktioniert der obige Code für C AND C++ - Compiler.

+0

+1 für die Überprüfung in beiden Compilern und erneute Überprüfung nach Änderungen. –

1

Ich habe auch Boost :: Dateisystem wie in einer anderen Antwort oben angegeben. Ich wollte nur hinzufügen, dass, da die current_path() Funktion keine Std :: String zurückgibt, müssen Sie es konvertieren.

Hier ist, was ich getan habe:

std::string cwd = boost::filesystem::current_path().generic_string(); 
0

Sie eine neue Funktion erstellen können, die ich über die Verknüpfung zu einer Bibliothek wie boost vorziehen würde (es sei denn Sie bereits sind).

std::string getcwd() 
{ 
    char* buff;//automatically cleaned when it exits scope 
    return std::string(getcwd(buff,255)); 
}