vit*_*aut 16 c++ string printf iostream volatile
考虑这个(人为的)例子:
#include <cstdio>
#include <iostream>
int main() {
volatile char test[] = "abc";
std::printf("%s\n", test);
std::cout << test << "\n";
}
Run Code Online (Sandbox Code Playgroud)
使用GCC进行编译并运行会提供以下输出:
$ g++ test.cc
$ ./a.out
abc
1
Run Code Online (Sandbox Code Playgroud)
如您所见,printf打印时正确cout打印字符串1.为什么写cout产生1在这种情况下?
Mik*_*our 14
唯一合适的重载operator<<是for bool,所以数组被转换(通过指针)bool,true因为它的地址是非空的.1除非您使用std::boolalpha操纵器,否则输出为.
它不能使用const char *输出字符串的重载,或const void *输出指针值的重载,因为这些转换需要删除volatile限定符.隐式指针转换可以添加限定符,但不能删除它们.
要输出字符串,您必须抛弃限定符:
std::cout << const_cast<const char*>(test) << "\n";
Run Code Online (Sandbox Code Playgroud)
但请注意,这会给出未定义的行为,因为数组将被访问,就好像它不是volatile一样.
printf是一种老式的可变功能,没有类型安全.该%s说明符使得它解释说法是const char *,不管它实际上是.
该的std :: basic_ostream ::运算符<<只有一个过载const char*或const void*在这种情况下不匹配,因为你不能放弃挥发性没有投预选赛中,这部分内容在草案C++标准的部分4.4 资质转换它说:
如果"cv2 T"比"cv1 T"更符合cv,则可以将类型"指向cv1 T的指针"的prvalue转换为"指向cv2 T的指针"的prvalue.
所以它使用的是bool版本,因为它不是nullptr结果true.
如果从中删除volatile限定符test将提供您期望的结果.几个答案建议使用a const_cast来删除volatile限定符,但这是未定义的行为.我们可以看一下7.1.6.1 cv-qualifiers第6段的部分,它说:
如果尝试通过使用具有非volatile限定类型的glvalue来引用使用volatile限定类型定义的对象,则程序行为是未定义的.
const_cast在这种情况下产生一个prvalue但是取消引用该指针会产生一个lvalue,它将调用未定义的行为.