C和c++ #include指令中可以接受反斜杠吗?

Is the backslash acceptable in C and C++ #include directives?

本文关键字:c++ #include 指令      更新时间:2023-10-16

有两种常用的路径分隔符:Unix的正斜杠和DOS的反斜杠。安息吧,经典Mac冒号。如果在#include指令中使用,它们在c++ 11、c++ 03和C99标准的规则下是相等的吗?

C99说(§6.4.7/3):

如果字符'、、"、//或/*出现在

(脚注:因此,类似转义序列的字符序列会导致未定义的行为。)

c++ 03说(§2.8/2):

如果字符'或,或者字符序列/*或//出现在q字符序列或h字符序列中,或者字符"出现在h字符序列中,行为未定义。

(脚注:因此,类似转义序列的字符序列会导致未定义的行为。)

c++ 11说(§2.9/2):

在q-char-sequence或h-char-sequence中,字符'或或字符序列/*或//中的任何一个的出现都是由实现定义的语义有条件地支持的,字符&quot的出现也是如此;

(脚注:因此,类似于转义序列的字符序列可能会导致错误,被解释为与转义序列对应的字符,或者具有完全不同的含义,这取决于实现。)

因此,尽管任何编译器都可能选择在#include路径中支持反斜杠,但不太可能有任何编译器供应商不支持正斜杠,并且反斜杠很可能由于形成转义码而使某些实现出错。(编辑:显然MSVC以前需要反斜杠。也许在dos派生平台上的其他平台也是类似的。我还能说什么呢

c++ 11 似乎放宽了规则,但"有条件支持";没有意义地优于"导致未定义行为"。这个变化更多地反映了某些流行编译器的存在,而不是描述一个可移植的标准。

当然,这些标准中都没有提到有路径这种东西。有一些文件系统根本没有路径!然而,许多库都假定路径名,包括POSIX和Boost,因此需要一种可移植的方式来引用子目录中的文件是合理的。

正斜杠是正确的;预编译器将在每个平台上做任何事情来获得正确的文件。

这取决于你对"可接受"的定义。

斜杠在两种意义上是可接受的,而反斜杠则不可接受。

如果你正在编写C99、c++ 03或C1x,反斜杠是未定义的,而斜杠是合法的,所以在这个意义上,反斜杠是不可接受的。

但这对大多数人来说是无关紧要的。如果您正在编写c++ 1x,其中反斜杠是有条件支持的,并且您正在编写的平台支持它们,那么它们是可以接受的。如果你正在编写C99/c++ 03/C1x的"扩展方言"来定义反斜杠,也一样。更重要的是,这个"可接受"的概念在大多数情况下都是毫无意义的。没有任何C/c++标准定义斜杠的含义(或者在条件支持的情况下,反斜杠的含义)。头文件名以实现定义的方式映射到源文件,句号。如果您有一个文件的层次结构,并且您在#include指令中询问是否使用反斜杠或斜杠来可移植地引用它们,那么答案是:两者都不可移植。如果您想编写真正可移植的代码,就不能使用头文件的层次结构——实际上,可以论证的是,您最好的选择是在单个源文件中编写所有内容,并且除了标准头文件之外不要#include任何内容。

然而,在现实世界中,人们通常想要"足够便携",而不是"严格便携"。POSIX标准规定了斜杠的含义,甚至在POSIX之外,大多数现代平台——包括Win32(和Win64)、Symbian等嵌入式和移动平台的交叉编译器——都以POSIX的方式对待斜杠,至少在C/c++ #包含指令的情况下是这样。任何不这样做的平台,可能都没有办法让你把源代码树放到上面,处理你的makefile/等等。等等,所以#include指令将是您最不需要担心的。如果这是你所关心的,那么斜杠是可以接受的,但反斜杠是不可接受的。

黑色斜杠是未定义的行为,即使使用斜杠,您也必须小心。C99标准规定:

如果字符',,",//或/*出现在<和>分隔符,行为为未定义的。类似地,如果字符'、、//或/*出现在分隔符之间的序列,行为未定义。

始终使用正斜杠-它们适用于更多平台。从技术上讲,反斜杠在c++ 03(标准为2.8/2)中会导致未定义的行为。

标准规定#include:

搜索实现定义的位置序列由指定序列之间唯一标识的报头的分隔符,并导致该指令被头文件的全部内容。如何在标题中指定位置标识是实现定义的。

注意最后一句