C++ 为什么ostream会为定义为“volatile char[]”的字符串打印“1”?
考虑这个(人为的)例子: 如您所见,C++ 为什么ostream会为定义为“volatile char[]”的字符串打印“1”?,c++,string,printf,iostream,volatile,C++,String,Printf,Iostream,Volatile,考虑这个(人为的)例子: 如您所见,printf正确打印字符串,而cout打印1。在这种情况下,为什么写入cout会产生1 “指针指向cv1 T”类型的PR值可转换为PR值 如果“cv2 T”比“cv1 T”更符合cv条件,则键入“指向cv2 T的指针” 因此它使用的是bool版本,由于它不是nullptr,因此结果是true 如果从test中删除volatile限定符,这将提供您期望的结果。一些答案建议使用const\u cast删除volatile限定符,但这是未定义的行为。我们可以通过查看
printf
正确打印字符串,而cout
打印1
。在这种情况下,为什么写入cout
会产生1
“指针指向cv1 T”类型的PR值可转换为PR值
如果“cv2 T”比“cv1 T”更符合cv条件,则键入“指向cv2 T的指针”
因此它使用的是bool
版本,由于它不是nullptr
,因此结果是true
如果从test
中删除volatile限定符,这将提供您期望的结果。一些答案建议使用const\u cast
删除volatile限定符,但这是未定义的行为。我们可以通过查看第7.1.6.1节来了解cv限定符第6段,其中说明:
如果试图引用由
通过使用带有
非易失性限定类型,程序行为未定义
const_cast
在这种情况下,会生成一个prvalue,但取消引用该指针会生成一个左值,该左值将调用未定义的行为。通过最少的web搜索找到的操作符答案的唯一合适重载:
简短回答:cout
由于volatile
限定符,正在将对象解释为bool
。这是重载的一个怪癖,是volatile
限定符将其强制转换为bool
,请尝试:
std::cout << const_cast<char*>(test) << "\n";
std::coutvolatile char[N]
匹配bool
优于const char*
。事实上,它根本不匹配constchar*
。@sharth太棒了,我甚至没想过要找一个dup。他们很接近,可能会很好地合并。这在技术上合法吗?Canoperator使用类型转换的答案具有未定义的行为:C++14[dcl.type.cv]p6说“如果试图通过使用glvalue和非易失性限定类型引用使用易失性限定类型定义的对象,则程序行为未定义。”您通常只能通过元素上的手写循环与易失性数组进行交互。@JeffreyYasskin我想知道这一点,但在这种情况下,const_cast
会产生一个prvalue
,据我所知,但我还没有详细考虑。@ShafikYaghmour:const_cast
会产生一个prvalueconst char*
指向volatile数组的第一个元素([expr.const.cast])。但这仅仅意味着指针是一个右值,而不是它指向的任何东西。取消对该指针的引用会产生一个引用第一个元素([expr.unary.op])的左值,该元素会给出未定义的行为。@RaymondChen:是的,你说得对,它会给出未定义的行为。我添加了一个警告。这个答案有未定义的行为:C++14[dcl.type.cv]p6说“如果试图通过使用非易失性限定类型的glvalue引用使用易失性限定类型定义的对象,则程序行为未定义。”@JeffreyYasskin猜测该变量相当<代码>易失性
!;)
$ g++ test.cc
$ ./a.out
abc
1
std::cout << const_cast<const char*>(test) << "\n";
std::cout<< (char*)test <<std::endl;
std::cout << const_cast<char*>(test) << "\n";