所以我正在阅读 learncpp 教程,并且我试图打印 char 指针的地址,因为当你这样做时:
char c{'i'};
cout << &c << endl;
Run Code Online (Sandbox Code Playgroud)
它只会打印字符串“i”,因为我猜编译器会识别一个指向字符数组的字符指针,这是一个字符串(但是我不明白为什么它只打印“i”,因为没有 '\0 ' 在字符“i”之后)。
不管怎样,我然后尝试将 char 指针静态转换为 int 指针,以便打印地址:
char c{'i'};
cout << static_cast<int*>(&c) << endl;
Run Code Online (Sandbox Code Playgroud)
但这甚至无法编译,我有一个错误“从类型 << char* >> 到类型 << int* >> 的 static_cast 无效”。
最后,我简单地尝试了这样的 C 类型转换:
char c{'i'};
cout << (int*)(&c) << endl;
Run Code Online (Sandbox Code Playgroud)
它起作用了,它打印了一个地址。
所以我的问题是:
谢谢
首先,static_cast<int*>(&c)将会失败,因为static_cast只允许非常特定的类型转换子集。例如,您可以static_cast在数字类型之间,或者在通过继承相关的两个类类型之间(即一个在继承层次结构中的某个点继承另一个)。
您所做的只是尝试将地址“重新解释”为不同类型的地址。原因是 C++std::ostream重载operator<<了const char*. 如果您只想打印地址本身,标准约定是转换为void*viastatic_cast<void*>(&c)或只是(void*)&c如果您可以使用 C 风格的转换。void*基本上是一个没有类型信息的指针,如果您只想打印出地址本身的值,那么它就很完美。
C 风格案例编译的原因是因为 C 风格强制转换采用了非常……我们可以说是有风险的……方法来执行转换。允许执行const_cast、reinterpret_cast、 和static_cast- 任何必要的操作 - 以便执行您指定的转换。cppreference.com上详细介绍了此行为。
至于为什么char*直接打印的例子尽管没有被终止却只打印单个字符:未定义的行为是未定义的。显然,碰巧(使用此编译器)可执行文件恰好紧随其后有一个零(空)字节,无论它在哪里。编译器甚至可能意识到您分配了一个值但从未修改它,因此它甚至可能不在堆栈中(它可能在data可执行文件的段中)。这个故事的寓意就是不要引发未定义的行为。