在以下示例中:
cout<<"\n"[a==N];
我对[]
选项在cout
中的作用一无所知,但当a
的值等于N
时,它不会打印换行符。< / p>
答案 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.5
在4.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+42
和42+array
之间没有区别。这会导致有趣的混淆:如果您的目标是彻底混淆代码,请使用42[array]
代替array[42]
。不言而喻,如果您的目标是编写可理解的,可维护的代码,那么编写42[array]
是一个可怕的想法。
布尔值如何转换为整数。
给定a[b]
形式的表达式,a
或b
必须是指针表达式而另一个;另一个必须是整数表达式。给定表达式"\n"[a==N]
,"\n"
表示该表达式的指针部分,a==N
表示表达式的整数部分。这里,a==N
是一个布尔表达式,其计算结果为false
或true
。整数提升规则指定false
变为0,true
在提升为整数时变为1。
字符串文字如何降级为指针。
当需要指针时,C和C ++中的数组很容易降级为指向数组第一个元素的指针。
如何实现字符串文字。
每个C风格的字符串文字都附加空字符'\0'
。这意味着您的"\n"
的内部代表是数组{'\n', '\0'}
。
鉴于上述情况,假设a==N
评估为false
。在这种情况下,行为在所有系统中都有明确定义:您将获得换行符。另一方面,如果a==N
评估为true
,则行为高度依赖于系统。根据对问题答案的评论,Windows不会那样。在类似Unix的系统中,std::cout
被传送到终端窗口,行为相当温和。没有任何事情发生。
仅仅因为你可以编写这样的代码并不意味着你应该这样做。永远不要写那样的代码。