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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12971499/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 16:49:08  来源:igfitidea点击:

How to get the file separator symbol in standard C/C++ : / or \?

c++cfilec++11filesystems

提问by Vincent

I would like to write a function :

我想写一个函数:

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

that returns the file separator of the system in standard C/C++/C++11 ? (I mean slash or backslash depending on the system). Is there a way to achieve this ?

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

回答by simonc

I'm not sure how to do it other than by checking ifdefs

除了检查 ifdefs 之外,我不知道该怎么做

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

or (as suggested by PaperBirdMaster)

或(根据 PaperBirdMaster 的建议)

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

回答by Overblade

If your compiler already offers c++17 capabilities, then you can use std::experimental::filesystem::path::preferred_separatorwhich should return either /or \depending on your platform.

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

See thisfor more information.

有关更多信息,请参阅内容。

回答by twid

that can be something like this

这可能是这样的

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

回答by David C.

This question is really hinting at a much nastier problem.

这个问题确实暗示了一个更棘手的问题。

If you simply care about UNIX vs. Winodws and you only care about directories and files, then what you've already seen will (mostly) work, but the more generic issue of splicing a path name into its components is a much uglier problem. Depending on the platform, a path may include one or more of:

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

  • Volume identifier
  • List of directories
  • File-name
  • Sub-stream within the file
  • Version number
  • 卷标识符
  • 目录列表
  • 文档名称
  • 文件内的子流
  • 版本号

While there are 3rd party libraries (like various CPAN Perl modules, Boost, and others) for this, and every OS includes system functions for this, there's nothing built-in to C for this and the C++ standard only gained this functionality (by incorporating the Boost module) in 2017.

虽然有 3rd 方库(如各种 CPAN Perl 模块、Boost 等),并且每个操作系统都包含用于此的系统函数,但 C 没有内置任何内容,C++ 标准仅获得了此功能(通过合并Boost 模块)在 2017 年。

Some examples of what such a function may need to deal with are:

此类函数可能需要处理的一些示例是:

  • UNIX and UNIX-like systems use a list of strings separated by "/" characters, with a leading "/" to indicate an absolute path (vs. a relative path). In some contexts (like NFS), there may also be a host-name prefix (with a ":" delimiter)
  • DOS and DOS-derived OS's (Windows, OS/2 and others) use "\" as a directory separator (with the APIs also accepting "/"), but paths may also be prefixed with volume information. It could be a drive letter ("C:"), or a UNC share name ("\\MYSERVER\SHARE\") There are additional prefixes to represent different kinds of servers and suffixes to represent non-default streams within a file.
  • Macs (Classic Mac OS, Carbon and some Cocoa APIs) use ":" as a directory separator, with the first term being a volume name, not a directory name. Mac files may also contain sub-streams ("forks"), which are accessed via the same name using special-purpose APIs. This is especially important for the resource fork, which is used extensively in classic Mac software.
  • Mac OS X, when using the UNIX APIs generally does what UNIX-like systems do, but they can also represent named sub-streams ("forks") by suffixing a "." followed by the fork-name to the file-name.
  • The latest versions of Cocoa (Mac OS X, iOS, etc.) recommend using a URL-based API to represent files, due to the ever-increasing complexity of this problem. Think about things like cloud-based documents and other complicated networked file systems.
  • VMS is pretty complicated (https://web.archive.org/web/20160324205714/http://www.djesys.com/vms/freevms/mentor/vms_path.html), but it has components that represent a volume, directory-path, file and file-revision.
  • UNIX 和类 UNIX 系统使用由“/”字符分隔的字符串列表,前导“/”表示绝对路径(相对于相对路径)。在某些情况下(如 NFS),也可能有主机名前缀(带有“:”分隔符)
  • DOS 和 DOS 派生的操作系统(Windows、OS/2 和其他)使用“\”作为目录分隔符(API 也接受“/”),但路径也可能以卷信息为前缀。它可以是驱动器号(“C:”)或 UNC 共享名称(“\\MYSERVER\SHARE\”)。还有其他前缀表示不同类型的服务器,后缀表示文件中的非默认流。
  • Mac(经典 Mac OS、Carbon 和一些 Cocoa API)使用“:”作为目录分隔符,第一个术语是卷名,而不是目录名。Mac 文件还可能包含子流(“fork”),这些子流可以使用专用 API 通过同名访问。这对于在经典 Mac 软件中广泛使用的资源分叉尤其重要。
  • Mac OS X,在使用 UNIX API 时,通常执行类 UNIX 系统所做的工作,但它们也可以通过后缀“.”来表示命名子流(“fork”)。后跟 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、文件和文件修订。

There are many others as well.

还有很多其他的。

It is worth noting that the C++17 filesystem library does not cover all of these possibilities. The std::filesystem::pathconsists of an optional root-name(a volume identifier), an optional root-directory(to identify absolute paths), and a sequence of filenames separated by directory separators. This covers everything likely to be valid on UNIX platforms and the majority of use-cases for other platforms, but is not comprehensive. For example, it does not have any support for sub-streams (relying on the OS to somehow map them onto a file name - which is done by Mac OS X, but not classic MacOS). It also does not include support for file version numbers.

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

See also Wikipedia's entry on Pathand the C++17 std::filesystem::pathclass

另请参阅维基百科关于 Path和 C++17 std::filesystem::path的条目

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

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

I recommend you look at what you want to do with the directory separator (extract the base-name, break a path into a list of directories, etc.) and write a function to do that. If you're using C++17 (and you are certain your code won't be compiled by a pre-17 C++ compiler) then you can (probably) use standard C++ library code to write a portable implementation of this function. If not, that function will need to use platform-specific #ifdefs for each platform you will be supporting, using a #errorif none of the conditions are met, to force you to to add conditions for unexpected platforms.

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

Or use a 3rd party library (like Boost) that includes functions for all of this, if that is acceptable.

或者使用包含所有这些功能的 3rd 方库(如 Boost),如果这是可以接受的。

回答by Fruity Nutty

The accepted answer does not work under Cygwin. Cygwin compiled programs running on Windows can use the Windows style '\' separator, but it does not define _WIN32 or the likes. A modified solution that works under Cygwin:

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

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

or

或者

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

回答by SYANiDE

I'm surprised no one has offered the following. This builds a bit on what others are offering here.

我很惊讶没有人提供以下内容。这建立在其他人在这里提供的基础上。

Although In this example I'm trying to dynamically grab the name of the executable being run for usage, it wouldn't be too hard to make the jump and reapply this however you need.

虽然在这个例子中我试图动态地获取正在运行的可执行文件的名称以供使用,但是根据需要进行跳转并重新应用它并不会太难。

Windows uses forward slash to denote arguments. So you could check for that first in the first argument argv[0], which contains the name of the program being run.

Windows 使用正斜杠来表示参数。因此,您可以在第一个参数中首先检查该参数argv[0],该参数包含正在运行的程序的名称。

Note the following results in stripping the pathname previous of the last slash, leaving sepdas the filename of the program.

请注意以下结果会删除最后一个斜杠前面的路径名,保留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');
}

But in all reality, this is pretty dirty and with Windows' most recent move to include Bash (not yet implemented at this time), this may produce unexpected or unanticipated results.

但实际上,这是非常肮脏的,并且随着 Windows 最近包含 Bash 的举措(此时尚未实施),这可能会产生意外或意外的结果。

It's also not as sane and impervious to errors as what others have offered, particularly #ifdef _WIN32.

它也不像其他人提供的那样理智和不受错误影响,尤其是#ifdef _WIN32.