cout <<“\ n”; 做?
在以下示例中:
cout<<"\n"[a==N];
我不知道[]
选项在cout
做了什么,但是当a的值等于N
时,它不打印换行符。
我不知道[]选项在cout中做了什么
这实际上不是一个选项,正在发生的是"\n"
是一个string文字 。 一个string文字的数组types为n常量字符 , []
只是一个字符数组的索引,在这种情况下包含:
\n\0
note \0
被附加到所有string文字。
==
运算符的结果为true或false ,因此索引将为:
-
0
如果为假,如果a
不等于N
导致\n
-
1
如果为真,如果a
等于N
,则导致\0
这是相当神秘的,可以用一个简单的if
代替。
参考C ++ 14标准( Lightness证实草案符合实际标准 )与最接近的草案是N3936 2.14.5
string文字[lex.string]说( 强调我的 ):
string常量的types为“n常量字符数组” ,其中n是下面定义的string大小,并具有静态存储持续时间(3.7)。
和:
经过任何必要的连接后,在翻译阶段7(2.2)中, '\ 0'被附加到每个string文字,以便扫描string的程序可以find它的结尾。
第4.5
节[conv.prom]说:
一个types为bool的prvalue可以被转换为inttypes的prvalue,其中false为零,true为真。
将空字符写入文本stream
有人声称写一个空字符( \0
)到一个文本stream是未定义的行为。
据我所知,这是一个合理的结论, cout
是用Cstream来定义的,正如我们从27.4.2
[narrow.stream.objects]中可以看到的那样:
对象cout控制输出到与在<cstdio>(27.9.2)中声明的对象stdout相关的stream缓冲区。
以及7.21.2
节中的C11草案标准说:
[…]从文本stream中读取的数据只有在以下情况下才会与先前写入该数据stream的数据相比较:数据仅由打印字符和控制字符水平制表符和换行符组成;
打印字符在7.4
字符处理<ctype.h>中 :
[…]术语控制字符是指不是打印字符的特定于语言环境的一组字符的成员.199)所有字母和数字都是打印字符。
用脚注199
说:
在使用七位US ASCII字符集的实现中,打印字符是那些值从0x20(空格)到0x7E(代字号)的字符。 控制字符是那些值从0(NUL)到0x1F(US),字符0x7F(DEL)的字符。
最后我们可以看到发送一个空字符的结果没有被指定,我们可以看到这是来自第4
节Conformance的未定义的行为:
未定义的行为在本标准中用“未定义的行为”或者没有任何明确的行为定义来表示。[…]
我们也可以看看C99的理由 :
在文本streamI / O中需要保留的字符集是编写C程序所需的字符集; 其目的是标准应该允许C翻译器以最便携的方式书写。 控制字符如backspace不是必需的,所以它们在文本stream中的处理不是强制性的。
cout<<"\n"[a==N];
我不知道[]选项在cout中做了什么
在C ++运算符优先级表中 , operator []
比operator <<
更紧密,因此您的代码等同于:
cout << ("\n"[a==N]); // or cout.operator <<("\n"[a==N]);
换句话说, operator []
不直接与cout
做任何事情。 它仅用于索引string文字"\n"
例如for(int i = 0; i < 3; ++i) std::cout << "abcdef"[i] << std::endl;
将在屏幕上的连续行上打印字符a,b和c。
因为C++
中的string文字 总是以空字符( '\0'
, L'\0'
, char16_t()
等)结尾,所以string文字"\n"
是一个const char[2]
'\n'
和'\0'
在内存布局中,这看起来像:
+--------+--------+ | '\n' | '\0' | +--------+--------+ 0 1 <-- Offset false true <-- Result of condition (a == n) a != na == n <-- Case
所以如果a == N
为真(提升为1),如果结果为假,则expression式"\n"[a == N]
产生'\0'
和'\n'
。
它在function上类似(不相同):
char anonymous[] = "\n"; int index; if (a == N) index = 1; else index = 0; cout << anonymous[index];
valueof "\n"[a==N]
是'\n'
或'\0'
typeof "\n"[a==N]
是const char
如果打算不打印任何东西(根据平台和目的,可能与打印'\0'
不同),则首选以下代码行:
if(a != N) cout << '\n';
即使您的意图是在stream中写入'\0'
或'\n'
,也可以使用可读代码:
cout << (a == N ? '\0' : '\n');
这可能是作为一种奇怪的写作方式
if ( a != N ) { cout<<"\n"; }
[]
运算符从数组中select一个元素。 string"\n"
实际上是两个字符的数组:一个新行'\n'
和一个string终止符'\0'
。 所以cout<<"\n"[a==N]
将打印'\n'
字符或'\0'
字符。
麻烦的是,您不允许在文本模式下将'\0'
字符发送到I / Ostream。 该代码的作者可能已经注意到似乎没有任何事情发生,所以他认为cout<<'\0'
是一种无所事事的安全方式。
在C和C ++中,由于未定义行为的概念,这是一个非常糟糕的假设。 如果程序做了一些不在标准或特定平台的规范范围内的事情,任何事情都可能发生。 在这种情况下,一个相当可能的结果就是这个stream将完全停止工作 – 根本不会有更多的输出到cout
。
总之,效果是,
“如果
a
不等于N
,打印一个换行符,否则我不知道,崩溃什么的。
道德就是,不要这么写东西。
它不是cout
的选项,而是数组索引"\n"
数组索引[a==N]
计算为[0]或[1],并索引由"\n"
表示的包含换行符和空字符的字符数组。
然而,通过nost到iostream将会有未定义的结果,最好传递一个string:
cout << &("\n"[a==N]) ;
然而,这两种情况下的代码都不是特别明智的,除了混淆以外,没有特别的用途。 不要把它看作是好的做法的一个例子。 大多数情况下,以下情况更为可取:
cout << (a != N ? "\n" : "") ;
要不就:
if( a != N ) cout << `\n` ;
以下每行将生成完全相同的输出:
cout << "\n"[a==N]; // Never do this. cout << (a==N)["\n"]; // Or this. cout << *((a==N)+"\n"); // Or this. cout << *("\n"+(a==N)); // Or this.
正如其他答案已经指定,这与std::cout
无关。 这是一个后果
-
如何在C和C ++中实现原始(非重载)下标操作符。
在这两种语言中,如果array
是一个C风格的基元array[42]
,array[42]
是*(array+42)
语法糖。 更糟糕的是,array+42
和42+array
没有区别。 这导致了一个有趣的混淆:如果您的目标是完全混淆您的代码,请使用42[array]
而不是array[42]
。 不用说,如果你的目标是编写可理解的,可维护的代码,写42[array]
是一个可怕的想法。 -
如何布尔变换为整数。
给定formsa[b]
的expression式,a
或b
必须是指针expression式,而另一个则是指针expression式。 另一个必须是一个整数expression式。 给定expression式"\n"[a==N]
,"\n"
表示该expression式的指针部分,并且a==N
表示expression式的整数部分。 这里,a==N
是一个布尔expression式,其值为false
或true
。 整数提升规则指定false
0,在提升为整数时为true
。 -
string文字如何降级成指针。
当需要指针时,C和C ++中的数组很容易降级成指向数组的第一个元素的指针。 -
如何实现string文字。
每个C风格string文字都附加了空字符'\0'
。 这意味着你的"\n"
的内部表示是数组{'\n', '\0'}
。
鉴于以上,假设a==N
评估为false
。 在这种情况下,所有系统的行为都是明确的:你会得到一个换行符。 另一方面,如果a==N
评估为true
,则该行为是高度依赖于系统的。 基于评论的问题的答案,Windows不会那样。 在类似Unix的系统上, std::cout
被传送到terminal窗口,这种行为是非常温和的。 什么都没发生。
只是因为你可以写这样的代码并不意味着你应该。 不要这样写代码。