如何在标准C/C++中获取文件分隔符号:/或\?

Vin*_*ent 23 c c++ filesystems file c++11

我想写一个函数:

inline char separator()
{
    /* SOMETHING */
}
Run Code Online (Sandbox Code Playgroud)

在标准C/C++/C++ 11中返回系统的文件分隔符?(我的意思是斜杠或反斜杠取决于系统).有没有办法实现这个目标?

sim*_*onc 38

除了通过检查ifdef,我不知道该怎么做

inline char separator()
{
#ifdef _WIN32
    return '\\';
#else
    return '/';
#endif
}
Run Code Online (Sandbox Code Playgroud)

或(由PaperBirdMaster建议)

const char kPathSeparator =
#ifdef _WIN32
                            '\\';
#else
                            '/';
#endif
Run Code Online (Sandbox Code Playgroud)

  • 只需注意 - Windows也支持正斜杠(/)作为路径分隔符. (17认同)
  • 所有 Windows 版本都定义 __WIN32 ?? (2认同)
  • 另一个注意事项:为什么是内联函数而不是`const char`? (2认同)
  • 我只是按照 OP 建议的风格回复。你是对的,`const char` 也一样好。我会将其添加到答案中 (2认同)
  • @einpoklum 好问题。我的评论并不完全正确。Win32 API 函数接受斜杠作为路径分隔符,并在调用 NT API 函数时将其转换为反斜杠(处理以 \\?\ 开头的路径时除外)。可以在 https://msdn.microsoft.com/en-us/library/aa365247.aspx 上找到详细信息。 (2认同)

Dav*_* C. 12

这个问题真的暗示了一个更糟糕的问题.

如果您只关心UNIX与Winodws并且只关心目录和文件,那么您已经看到的(大多数)将会工作,但是将路径名拼接到其组件中的更通用的问题是一个更加丑陋的问题.根据平台,路径可能包括以下一项或多项:

  • 卷标识符
  • 目录列表
  • 文件名
  • 文件中的子流
  • 版本号

虽然有第三方库(比如各种CPAN Perl模块,Boost等),并且每个操作系统都包含系统功能,但是没有内置于C的C++标准只能获得此功能(通过合并) 2017年的Boost模块).

这种功能可能需要处理的一些例子是:

  • UNIX和类UNIX系统使用由"/"字符分隔的字符串列表,前导"/"表示绝对路径(相对于相对路径).在某些上下文(如NFS)中,可能还有一个主机名前缀(带有":"分隔符)
  • DOS和DOS派生的操作系统(Windows,OS/2和其他)使用"\"作为目录分隔符(API也接受"/"),但路径也可以以卷信息为前缀.它可以是驱动器号("C:")或UNC共享名称("\\ MYSERVER\SHARE \").还有其他前缀表示不同类型的服务器和后缀,以表示文件中的非默认流.
  • Mac(Classic Mac OS,Carbon和一些Cocoa API)使用":"作为目录分隔符,第一个术语是卷名,而不是目录名.Mac文件还可能包含子流("forks"),这些子流使用专用API通过相同的名称访问.这对于经典Mac软件中广泛使用的资源分支尤为重要.
  • 使用UNIX API时,Mac OS X通常会执行类似UNIX的系统,但它们也可以通过后缀"."来表示命名子流("forks").然后是fork-name到文件名.
  • 最新版本的Cocoa(Mac OS X,iOS等)建议使用基于URL的API来表示文件,因为此问题的复杂性不断增加.想想基于云的文档和其他复杂的网络文件系统.
  • VMS非常复杂(https://web.archive.org/web/20160324205714/http://www.djesys.com/vms/freevms/mentor/vms_path.html),但它有代表卷,目录的组件-path,file和file-revision.

还有很多其他的.

值得注意的是,C++ 17文件系统库并未涵盖所有这些可能性.它std::filesystem::path由可选的根名称(卷标识符),可选的根目录(用于标识绝对路径)和由目录分隔符分隔的文件名序列组成.这涵盖了在UNIX平台上可能有效的所有内容以及其他平台的大多数用例,但并不全面.例如,它没有任何子流支持(依靠操作系统以某种方式将它们映射到文件名 - 这是由Mac OS X完成的,但不是经典的MacOS).它也不包括对文件版本号的支持.

另请参阅Wikipedia在Path和C++ 17 std :: filesystem :: path上的条目

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

我建议您查看目标分隔符要执行的操作(提取基本名称,将路径分解为目录列表等)并编写一个函数来执行此操作.如果您正在使用C++ 17(并且您确定您的代码不会被17之前的C++编译器编译),那么您可以(可能)使用标准C++库代码来编写此函数的可移植实现.如果没有,该功能将需要为#ifdef您将支持的每个平台使用特定于平台的s,#error如果没有满足任何条件,则使用它来强制您为意外平台添加条件.

或者使用包含所有这些功能的第三方库(如Boost),如果可以接受的话.


twi*_*wid 11

这可能是这样的

#if defined(WIN32) || defined(_WIN32) 
#define PATH_SEPARATOR "\\" 
#else 
#define PATH_SEPARATOR "/" 
#endif 
Run Code Online (Sandbox Code Playgroud)

  • 注意:就像接受的答案一样,您可能希望将符号定义为char literal(使用单引号) (2认同)
  • @ardnew,这取决于。如果你想在 C 中的字符串指针上使用它,那么它是一个字符还是一个字符串没有太大区别,你只需要为 `snprintf()` 选择正确的格式说明符。另一方面,如果您想在文字字符串上使用字符串版本,则它更方便。使用字符串版本,您只需编写类似 `"base_path" PATH_SEPARATOR "final_path"` 的内容就可以连接文字。如果将分隔符定义为字符,则无法执行此操作。 (2认同)

Ove*_*ade 11

如果您的编译器已经提供了c ++ 17功能,则可以使用std::experimental::filesystem::path::preferred_separatorwhich返回/\取决于您的平台。

请参阅以获取更多信息。

  • 小na,没什么大不了的。关于`preferred_separator`应该是什么的文档只是一个例子;即在Windows上,您将获得一个“ \\”,而在POSIX上,您将获得一个“ /”。其他平台可能会提供其他结果。 (2认同)

小智 6

接受的答案在Cygwin下不起作用.在Windows上运行的Cygwin编译程序可以使用Windows样式的'\'分隔符,但它没有定义_WIN32等.在Cygwin下运行的修改后的解决方案:

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

要么

const char kPathSeparator =
#if defined _WIN32 || defined __CYGWIN__
    '\\';
#else
    '/';
#endif
Run Code Online (Sandbox Code Playgroud)