Siv*_*sad 60 c++ cout string-literals
在以下示例中:
cout<<"\n"[a==N];
我不知道该[]选项的作用cout,但是当值a等于时,它不会打印换行符N.
Sha*_*our 70
我不知道[]选项在cout中的作用
这实际上不是一个cout选项,正在发生的事情是,"\n"是一个文字字符串.字符串文字的类型数组为n const char,[]它只是字符数组的索引,在本例中包含:
\n\0
note \0附加到所有字符串文字.
该==操作的结果无论是真或假,因此指数将是:
0如果为假,如果a不相等则N导致\n1如果为真,如果a等于N结果\0这是相当神秘的,可以用简单的替换if.
作为参考,C++ 14标准(Lightness确认草案符合实际标准),最接近的草案是N3936,在2.14.5字符串文字[lex.string]中说(强调我的):
string literal的类型为"const of n const char",其中n是下面定义的字符串的大小,并且具有静态存储持续时间(3.7).
和:
在任何必要的连接之后,在转换阶段7(2.2)中, '\ 0'被附加到每个字符串文字,以便扫描字符串的程序可以找到它的结尾.
部分4.5 [conv.prom]说:
bool类型的prvalue可以转换为int类型的prvalue,false变为零,true变为1.
将空字符写入文本流
声称将空字符(\0)写入文本流是未定义的行为.
据我所知,这是一个合理的结论,cout用C流来定义,正如我们从27.4.2 [narrow.stream.objects]中看到的那样:
对象cout控制输出到与对象标准输出相关联的流缓冲区,在<cstdio>(27.9.2)中声明.
和7.21.2 Streams部分的C11标准草案说:
[...]从文本流读入的数据必须与之前写入该流的数据相等,只有在以下情况下:数据仅由打印字符和控制字符水平制表符和换行符组成;
字符处理<ctype.h>中介绍了打印字符和打印字符:7.4 
[...]术语控制字符是指不能打印字符的特定于语言环境的字符集的成员.199)所有字母和数字都是打印字符.
用脚注199说:
在使用7位US ASCII字符集的实现中,打印字符是其值从0x20(空格)到0x7E(代字号)的字符; 控制字符是其值从0(NUL)到0x1F(US)的字符,以及字符0x7F(DEL).
最后我们可以看到发送空字符的结果没有指定,我们可以看到这是来自4Conformance 部分的未定义行为,其中说:
[...]未定义的行为在本国际标准中以"未定义的行为"或"省略任何明确的行为定义"一词另有说明.[...]
我们还可以看看C99的基本原理:
需要在文本流I/O中保留的字符集是编写C程序所需的字符集.意图是标准应该允许以最便携的方式编写C语言翻译器.为此目的不需要诸如退格之类的控制字符,因此不强制它们在文本流中的处理.
Moh*_*ain 39
Run Code Online (Sandbox Code Playgroud)cout<<"\n"[a==N];我不知道[]选项在cout中的作用
在C++运算符Precedence表中,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++被始终与空字符终止('\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为true(提升为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');
它可能是一种奇怪的写作方式
if ( a != N ) {
    cout<<"\n";
}
在[]操作者选择从数组中的一个元素.该字符串"\n"实际上是一个包含两个字符的数组:一个新行'\n'和一个字符串终止符'\0'.因此cout<<"\n"[a==N]将打印'\n'字符或'\0'字符.
问题是您不允许'\0'在文本模式下向I/O流发送字符.该代码的作者可能已经注意到似乎没有发生任何事情,因此他认为这cout<<'\0'是一种无所事事的安全方式.
在C和C++中,由于未定义行为的概念,这是一个非常糟糕的假设.如果程序执行了标准规范或特定平台未涵盖的内容,则可能发生任何事情.在这种情况下,一个相当可能的结果是流将完全停止工作 - 根本cout不会出现输出.
总之,效果是,
"如果
a不等于,则打印换行N.否则,我不知道.崩溃或其他什么."
...而道德是,不要如此隐秘地写东西.
它不是一个选项,cout而是一个数组索引"\n"
数组索引的[a==N]计算结果为[0]或[1],并对"\n"包含换行符和空字符的字符数组进行索引.
但是将nul传递给iostream将会产生未定义的结果,最好传递一个字符串:
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++中实现原始(非重载)下标运算符.
在这两种语言中,if 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通过管道传送到终端窗口,行为相当温和.什么都没发生.
仅仅因为你可以编写这样的代码并不意味着你应该这样做.永远不要写那样的代码.
| 归档时间: | 
 | 
| 查看次数: | 3419 次 | 
| 最近记录: |