web-dev-qa-db-ja.com

標準のC / C ++でファイル区切り記号を取得する方法:/または\?

関数を書きたい:

inline char separator()
{
    /* SOMETHING */
}

標準のC/C++/C++ 11でシステムのファイル区切りを返す(システムに応じて、スラッシュまたはバックスラッシュを意味します)。これを達成する方法はありますか?

26
Vincent

Ifdefsを確認する以外に、どうすればよいかわかりません

inline char separator()
{
#ifdef _WIN32
    return '\\';
#else
    return '/';
#endif
}

または(PaperBirdMasterの提案どおり)

const char kPathSeparator =
#ifdef _WIN32
                            '\\';
#else
                            '/';
#endif
37
simonc

この質問は、非常に厄介な問題をほのめかしています。

UNIXとWinodwsだけに関心があり、ディレクトリとファイルのみに関心がある場合、すでに見たものは(ほとんど)機能しますが、パス名をそのコンポーネントにスプライスするというより一般的な問題は、はるかに醜い問題です。プラットフォームに応じて、パスには次の1つ以上が含まれる場合があります。

  • ボリューム識別子
  • ディレクトリのリスト
  • ファイル名
  • ファイル内のサブストリーム
  • バージョンナンバー

これにはサードパーティのライブラリ(さまざまなCPAN Perlモジュール、Boostなど)があり、すべてのOSにはこのためのシステム関数が含まれていますが、Cに組み込まれているものはなく、C++標準はこの機能のみを組み込みました(組み込むことにより)ブーストモジュール)2017年に。

そのような関数が処理する必要があるかもしれないもののいくつかの例は:

  • UNIXおよびUNIXライクなシステムでは、「/」文字で区切られた文字列のリストを使用し、先頭に「/」を付けて絶対パス(対相対パス)を示します。一部のコンテキスト(NFSなど)では、ホスト名のプレフィックス(「:」区切り文字付き)が存在する場合もあります。
  • DOSおよびDOS派生のOS(Windows、OS/2など)は、ディレクトリ区切り文字として「\」を使用します(APIは「/」も受け入れます)。ただし、パスの前にボリューム情報を付けることもできます。これは、ドライブ文字( "C:")またはUNC共有名( "\\ MYSERVER\SHARE \")の可能性があります。異なる種類のサーバーを表すための追加のプレフィックスと、ファイル内のデフォルト以外のストリームを表すためのサフィックスがあります。
  • Mac(クラシックMac OS、Carbonおよび一部のCocoa API)は、ディレクトリ区切り文字として「:」を使用します。最初の用語は、ディレクトリ名ではなくボリューム名です。 Macファイルには、特別な目的のAPIを使用して同じ名前でアクセスされるサブストリーム(「フォーク」)が含まれている場合もあります。これは、クラシックMacソフトウェアで広く使用されているリソースフォークにとって特に重要です。
  • Mac OS Xは、UNIX APIを使用すると、一般にUNIXライクなシステムと同じように動作しますが、「。」を付けることで名前付きサブストリーム(「フォーク」)を表すこともできます。フォーク名からファイル名へと続きます。
  • Cocoaの最新バージョン(Mac OS X、iOSなど)では、この問題がますます複雑になるため、URLベースのAPIを使用してファイルを表すことをお勧めします。クラウドベースのドキュメントやその他の複雑なネットワークファイルシステムなどについて考えてください。
  • VMSはかなり複雑( https://web.archive.org/web/20160324205714/http://www.djesys.com/vms/freevms/mentor/vms_path.html )ですが、ボリューム、ディレクトリパス、ファイル、ファイルリビジョンを表すコンポーネント。

他にもたくさんあります。

C++ 17ファイルシステムライブラリがこれらの可能性のすべてをカバーしているわけではないことは注目に値します。 std::filesystem::pathは、オプションのroot-name(ボリューム識別子)、オプションのroot- directory(絶対パスを識別するため)、およびディレクトリ区切り文字で区切られたファイル名のシーケンス。これは、UNIXプラットフォームで有効である可能性が高いすべてと他のプラットフォームの大部分のユースケースをカバーしますが、包括的ではありません。たとえば、サブストリームはサポートされていません(OSを何らかの方法でファイル名にマッピングしているため、Mac OS Xでは実行されますが、クラシックMacOSでは実行されません)。また、ファイルバージョン番号のサポートも含まれていません。

Wikipediaのパスに関するエントリ およびC++ 17 std :: filesystem :: path クラスも参照してください

http://en.cppreference.com/w/cpp/filesystem

ディレクトリセパレーターで何をしたいか(ベース名を抽出し、パスをディレクトリのリストに分割するなど)を確認し、それを行う関数を作成することをお勧めします。 C++ 17を使用している場合(かつ、コードが17より前のC++コンパイラーによってコンパイルされないことが確実である場合)、(おそらく)標準のC++ライブラリコードを使用して、この関数の移植可能な実装を作成できます。そうでない場合、その関数は、サポートするプラットフォームごとにプラットフォーム固有の#ifdefsを使用する必要があります。条件が満たされない場合は#errorを使用して、予期しないプラットフォームの条件を追加するように強制します。 。

または、それが許容できる場合は、これらすべての機能を含むサードパーティライブラリ(Boostなど)を使用します。

12
David C.

それはこのようなものにすることができます

#if defined(WIN32) || defined(_WIN32) 
#define PATH_SEPARATOR "\\" 
#else 
#define PATH_SEPARATOR "/" 
#endif 
10
twid

コンパイラがすでにc ++ 17機能を提供している場合は、std::experimental::filesystem::path::preferred_separatorを使用できます。これにより、プラットフォームに応じて/または\が返されます。

詳細は this を参照してください。

9
Overblade

受け入れられた回答はCygwinでは機能しません。 Windowsで実行されているCygwinでコンパイルされたプログラムは、Windowsスタイルの '\'区切り文字を使用できますが、_WIN32などを定義していません。 Cygwinで動作する修正されたソリューション:

inline char separator()
{
#if defined _WIN32 || defined __CYGWIN__
    return '\\';
#else
    return '/';
#endif
}

または

const char kPathSeparator =
#if defined _WIN32 || defined __CYGWIN__
    '\\';
#else
    '/';
#endif
6
Fruity Nutty

C++ 17ではstd::filesystem::path::preferred_separatorを使用できるようになりました( see ):

#include <filesystem>
#include <iostream>

int main() {
    std::cout << "This OS separator: " << std::filesystem::path::preferred_separator;
}
0
João Paulo

誰もが以下を提供していないことに驚いています。これは、他の人がここで提供しているものに少し基づいています。

この例では、実行のために実行されている実行可能ファイルの名前を動的に取得しようとしていますが、必要に応じてジャンプして再適用することはそれほど難しくありません。

Windowsでは、スラッシュを使用して引数を示します。したがって、最初の引数argv[0]、実行中のプログラムの名前が含まれています。

次の結果では、最後のスラッシュの前のパス名が削除され、sepdはプログラムのファイル名のままになります。

#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');
}

しかし、現実にはこれはかなり汚いものであり、Bashを含めるWindowsの最新の動き(現時点ではまだ実装されていません)では、予期しない結果または予期しない結果が生じる可能性があります。

また、他の人が提供しているものほど、正気でエラーに影響されません。特に#ifdef _WIN32

0
SYANiDE