什么是cout<< “\ n” 个[A == N];做?

时间:2015-06-17 10:26:01

标签: c++ cout string-literals

在以下示例中:

cout<<"\n"[a==N];

我对[]选项在cout中的作用一无所知,但当a的值等于N时,它不会打印换行符。< / p>

5 个答案:

答案 0 :(得分:70)

  

我不清楚cout

中[]选项的用途

这实际上不是cout选项,发生的事情是"\n"string literal。字符串文字的类型数组为n const char []只是字符数组的索引,在本例中包含:

\n\0

note \0附加到所有字符串文字。

==运算符导致 true false ,因此索引将为:

  • 0如果为false,如果a不等于N导致\n
  • 1如果为true,如果a等于N导致\0

这是相当神秘的,可以用简单的if替换。

参考C ++ 14标准( Lightness确认草案与实际标准匹配),最近的草稿2.14.54.5字符串文字中[lex.string] 说(强调我的):

  

string literal 的类型为“n const char数组”,其中n为   如下定义的字符串大小,并具有静态存储持续时间   (3.7)。

  

在任何必要的连接之后,在翻译阶段7(2.2),   '\ 0'附加到每个字符串文字,以便扫描字符串的程序可以找到它的结尾。

部分\0 [conv.prom] 说:

  

bool类型的prvalue可以转换为int类型的prvalue   假成为零,真正成为一个。

将空字符写入文本流

声称将空字符(cout)写入文本流是未定义的行为。

据我所知,这是一个合理的结论,27.4.2是根据C流定义的,正如我们从7.21.2 [narrow.stream.objects]中看到的那样其中说:

  

对象cout控制输出到与声明的对象标准输出相关联的流缓冲区   &LT; cstdio&GT; (27.9.2)。

以及7.4 Streams 部分中的C11草案标准说:

  

[...]从文本流读入的数据必须与数据相等   只有在以下情况下才会写入该流:数据仅包含打印   字符和控制字符水平制表符和换行符;

打印字符包含在199 字符处理&lt; ctype.h&gt; 中:

  

[...]术语控制字符   指的是未打印的特定于语言环境的字符集的成员   字符.199)所有字母和数字都是打印字符。

脚注4说:

  

在使用七位US ASCII字符集的实现中,打印字符是那些   其值从0x20(空格)到0x7E(代字号);控制字符是那些   值从0(NUL)到0x1F(US),字符0x7F(DEL)。

最后我们可以看到没有指定发送空字符的结果,我们可以看到这是(符合性中未定义的行为,其中说明:

  

[...]否则是未定义的行为   本标准中用“未定义的行为”或“未定义的行为”表示   遗漏任何明确的行为定义。[...]

我们也可以查看N3936说:

  

需要在文本流I / O中保留的字符集是编写C所需的字符集   程式;意图是标准应该允许C语言翻译最大限度地写入   便携时尚。为此,不需要诸如退格之类的控制字符,因此它们是必需的   文本流中的处理不是强制性的。

答案 1 :(得分:39)

cout<<"\n"[a==N];
     

我不清楚cout

中[]选项的用途

C++ operator Precedence table中,operator []operator <<更紧密,因此您的代码相当于:

cout << ("\n"[a==N]);  // or cout.operator <<("\n"[a==N]);

或换句话说,operator []没有直接与cout做任何事情。它仅用于索引字符串文字"\n"

例如for(int i = 0; i < 3; ++i) std::cout << "abcdef"[i] << std::endl;将在屏幕上的连续行上打印字符a,b和c。

由于C++中的string literals 始终以空字符('\0'L'\0'char16_t()等)终止,字符串文字"\n"const char[2],其中包含字符'\n''\0'

在内存布局中,这看起来像:

+--------+--------+
|  '\n'  |  '\0'  |
+--------+--------+
0        1          <-- Offset
false    true       <-- Result of condition (a == n)
a != n   a == n     <-- Case

因此,如果a == N为真(提升为1),则表达式"\n"[a == N]会导致'\0''\n',如果结果为false。

功能相似(不相同):

char anonymous[] = "\n";
int index;
if (a == N) index = 1;
else index = 0;
cout << anonymous[index];

"\n"[a==N]的值为'\n''\0'

typeof "\n"[a==N]const char

如果打算不打印任何内容(可能与打印'\0'不同,具体取决于平台和目的),请选择以下代码行:

if(a != N) cout << '\n';

即使您打算在流上写'\0''\n',也更喜欢可读的代码,例如:

cout << (a == N ? '\0' : '\n');

答案 2 :(得分:9)

它可能是一种奇怪的写作方式

if ( a != N ) {
    cout<<"\n";
}

[]运算符从数组中选择一个元素。字符串"\n"实际上是一个包含两个字符的数组:新行'\n'和字符串终止符'\0'。因此cout<<"\n"[a==N]会打印'\n'字符或'\0'字符。

问题是您不允许以文本模式向I / O流发送'\0'字符。该代码的作者可能已经注意到似乎没有发生任何事情,所以他认为cout<<'\0'是一种无所事事的安全方式。

在C和C ++中,由于未定义行为的概念,这是一个非常糟糕的假设。如果程序执行了标准或特定平台规范未涵盖的内容,那么可以发生。在这种情况下,一个相当可能的结果是流将完全停止工作 - 根本不会出现cout的输出。

总之,效果是,

  

&#34;如果a不等于N,请打印换行符。否则,我不知道。崩溃什么的。&#34;

......道德是,不要把事情写得如此隐秘。

答案 3 :(得分:8)

它不是cout的选项,而是"\n"

的数组索引

数组索引[a==N]求值为[0]或[1],并索引由"\n"表示的包含换行符和空字符的字符数组。

但是将nul传递给iostream会产生未定义的结果,最好传递一个字符串:

cout << &("\n"[a==N]) ;

但是,在任何一种情况下,代码都不是特别明智,除了混淆之外没有任何特殊目的;不要把它当作良好做法的一个例子。在大多数情况下,以下情况更可取:

cout << (a != N ? "\n" : "") ;

或只是:

if( a != N ) cout << `\n` ;

答案 4 :(得分:8)

以下每一行都会生成完全相同的输出:

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+4242+array之间没有区别。这会导致有趣的混淆:如果您的目标是彻底混淆代码,请使用42[array]代替array[42]。不言而喻,如果您的目标是编写可理解的,可维护的代码,那么编写42[array]是一个可怕的想法。

  • 布尔值如何转换为整数。
    给定a[b]形式的表达式,ab必须是指针表达式而另一个;另一个必须是整数表达式。给定表达式"\n"[a==N]"\n"表示该表达式的指针部分,a==N表示表达式的整数部分。这里,a==N是一个布尔表达式,其计算结果为falsetrue。整数提升规则指定false变为0,true在提升为整数时变为1。

  • 字符串文字如何降级为指针。
    当需要指针时,C和C ++中的数组很容易降级为指向数组第一个元素的指针。

  • 如何实现字符串文字。
    每个C风格的字符串文字都附加空字符'\0'。这意味着您的"\n"的内部代表是数组{'\n', '\0'}


鉴于上述情况,假设a==N评估为false。在这种情况下,行为在所有系统中都有明确定义:您将获得换行符。另一方面,如果a==N评估为true,则行为高度依赖于系统。根据对问题答案的评论,Windows不会那样。在类似Unix的系统中,std::cout被传送到终端窗口,行为相当温和。没有任何事情发生。


仅仅因为你可以编写这样的代码并不意味着你应该这样做。永远不要写那样的代码。