Ich möchte eine Funktion schreiben:
inline char separator()
{
/* SOMETHING */
}
gibt das Dateiseparator des Systems in Standard C/C++/C++ 11 zurück? (Ich meine Slash oder Backslash je nach System). Gibt es einen Weg, dies zu erreichen?
Ich bin mir nicht sicher, wie ich das machen soll, indem ich ifdefs überprüfe
inline char separator()
{
#ifdef _WIN32
return '\\';
#else
return '/';
#endif
}
oder (wie von PaperBirdMaster vorgeschlagen)
const char kPathSeparator =
#ifdef _WIN32
'\\';
#else
'/';
#endif
Diese Frage weist auf ein viel schlimmeres Problem hin.
Wenn Sie sich einfach für UNIX vs. Winodws interessieren und nur für Verzeichnisse und Dateien sorgen, wird das, was Sie bereits gesehen haben, (meistens) funktionieren, aber das allgemeinere Problem, einen Pfadnamen in seine Komponenten zu spleißen, ist ein viel hässlicheres Problem. Abhängig von der Plattform kann ein Pfad ein oder mehrere der folgenden Elemente enthalten:
Zwar gibt es Drittanbieter-Bibliotheken (wie verschiedene CPAN-Perl-Module, Boost und andere), und jedes Betriebssystem enthält Systemfunktionen dafür, jedoch ist in C nichts eingebaut, und der C++ - Standard hat nur diese Funktionalität erhalten (durch Einbinden von) das Boost-Modul) im Jahr 2017.
Einige Beispiele, mit denen sich eine solche Funktion befassen muss, sind:
Es gibt auch viele andere.
Es ist erwähnenswert, dass die C++ 17-Dateisystembibliothek nicht alle diese Möglichkeiten abdeckt. std::filesystem::path
besteht aus einem optionalen root-name (einem Datenträgerbezeichner), einem optionalen root-verzeichnis (zur Identifizierung absoluter Pfade) und einer durch Verzeichnisseparatoren getrennten Folge von Dateinamen. Dies deckt alles ab, was wahrscheinlich auf UNIX-Plattformen und die Mehrzahl der Anwendungsfälle für andere Plattformen gilt, ist jedoch nicht umfassend. Zum Beispiel werden keine Sub-Streams unterstützt (abhängig vom Betriebssystem, um sie irgendwie einem Dateinamen zuzuordnen - dies wird von Mac OS X durchgeführt, nicht jedoch von klassischem MacOS). Es enthält auch keine Unterstützung für Dateiversionsnummern.
Siehe auch Wikipedia-Eintrag zu Path und C++ 17 std :: filesystem :: path class
http://en.cppreference.com/w/cpp/filesystem
Ich empfehle Ihnen, sich mit dem Verzeichnisseparator zu beschäftigen (extrahieren Sie den Basisnamen, brechen Sie einen Pfad in eine Liste von Verzeichnissen usw.) und schreiben Sie eine Funktion, um dies zu tun. Wenn Sie C++ 17 verwenden (und Sie sind sicher, dass Ihr Code nicht von einem C++ - Compiler vor 17 kompiliert wird), können Sie (wahrscheinlich) Standard-C++ - Bibliothekscode verwenden, um eine portable Implementierung dieser Funktion zu schreiben. Andernfalls muss diese Funktion plattformspezifische #ifdef
s für jede unterstützte Plattform verwenden. Wenn keine der Bedingungen erfüllt ist, muss #error
verwendet werden, um Bedingungen für unerwartete Plattformen hinzuzufügen.
Oder verwenden Sie eine Drittanbieter-Bibliothek (wie Boost), die Funktionen für all dies enthält, sofern dies akzeptabel ist.
das kann so etwas sein
#if defined(WIN32) || defined(_WIN32)
#define PATH_SEPARATOR "\\"
#else
#define PATH_SEPARATOR "/"
#endif
Die akzeptierte Antwort funktioniert nicht unter Cygwin. Cygwin-kompilierte Programme, die unter Windows ausgeführt werden, können das Windows-Trennzeichen '\' verwenden, definieren jedoch nicht _WIN32 oder ähnliches. Eine modifizierte Lösung, die unter Cygwin funktioniert:
inline char separator()
{
#if defined _WIN32 || defined __CYGWIN__
return '\\';
#else
return '/';
#endif
}
oder
const char kPathSeparator =
#if defined _WIN32 || defined __CYGWIN__
'\\';
#else
'/';
#endif
Wenn Ihr Compiler bereits C++ 17-Funktionen bietet, können Sie std::experimental::filesystem::path::preferred_separator
verwenden, der je nach Plattform entweder /
oder \
zurückgeben sollte.
Siehe this für weitere Informationen.
Jetzt mit C++ 17 ist es möglich, std::filesystem::path::preferred_separator
( siehe ):
#include <filesystem>
#include <iostream>
int main() {
std::cout << "This OS separator: " << std::filesystem::path::preferred_separator;
}
Ich bin überrascht, dass niemand folgendes angeboten hat. Dies baut ein wenig auf dem auf, was andere hier anbieten.
Obwohl in diesem Beispiel versucht wird, dynamisch den Namen der ausführbaren Datei zu ermitteln, die zur Verwendung ausgeführt wird, wäre es nicht zu schwer, den Sprung zu machen und diesen erneut anzuwenden, je nachdem, was Sie brauchen.
Windows verwendet einen Schrägstrich, um Argumente zu kennzeichnen. Sie können also zuerst im ersten Argument argv[0]
nach dem Namen des ausgeführten Programms suchen.
Beachten Sie die folgenden Ergebnisse, wenn Sie den Pfadnamen vor dem letzten Schrägstrich entfernen und sepd
als Dateinamen des Programms belassen.
#include <string.h>
#include <stdio.h>
int main(int argc, char *argv[]){
//int a = 1
//int this = (a == 1) ? 20 : 30; //ternary operator
//is a==1 ? If yes then 'this' = 20, or else 'this' = 30
char *sepd = (strrchr(argv[0], '\/') != NULL) ?
strrchr(argv[0], '\/') :
strrchr(argv[0], '\\');
printf("%s\n\n", sepd);
printf("usage: .%s <Host> \n\n", sepd);
while (getchar() != '\n');
}
Aber in Wirklichkeit ist das ziemlich schmutzig und mit der jüngsten Umstellung von Windows auf Bash (derzeit noch nicht implementiert) kann dies zu unerwarteten oder unerwarteten Ergebnissen führen.
Es ist auch nicht so vernünftig und fehleranfällig wie andere, insbesondere #ifdef _WIN32
.