问题描述
[我的问题有点奇怪,但现在改变它是不对的,因为它得到了很好的解释,但我正在用[更新].......[更新结束]标签编辑它以避免使即将访问我的帖子的访问者感到困惑]
C
#include<stdio.h>
int main()
{
float *q=NULL;
printf("%f\n",q);
}
0.000000
- 在 C 中输出为 0.000000
- 所以这里 q 是浮点型空指针还是仍然是 (void *) 型空指针?
- 我觉得它是 (void *) 类型。
- 因此格式不匹配(%f)和参数(void*)调用未定义 行为并导致此类错误类型输出
[更新] 但是你会填写我自己的问题的答案,我问的这么愚蠢的问题
基本上我很困惑,我觉得我必须打印一些浮点类型或空类型,但重点是我正在打印地址,所以使用 %f 来打印地址是愚蠢的。
显然 q 是浮点型指针,只是我觉得完全错误
通常我们使用 %u 来打印任何类型变量(int,char,float)的地址,但对于指针我们应该使用 %p
[更新结束]
C++
#include<iostream>
int main()
{
float *q=nullptr;
std::cout<<q;
}
0
- 在 C++ 中给出输出 0
- 我认为这很好,因为它给出了第一个内存块的地址作为指向 一无所有
- 如果 q 是 nullptr_t 类型,那么 C++11 应该给出 ambugity 错误 表示这里 q 是浮点型 nullptr。
[更新]
C 和 C++ 标准都指定空指针常量比较等于零 - 他们没有说明该地址处的内容。
显然 q 只是浮点型 nullptr
[更新结束]
所以,如果我的两个假设都是正确的,那么为什么在 C++ nullptr 中将其类型从 nullptr_t 更改为浮点类型,但在 C 中 NULL 并没有将其类型从 (void ) 更改为 (float) ?
[更新]
我在第一个 C 示例中第一个假设 q 是 (void*) 类型已经是错误的 和第二个假设,在第二个例子。 C++的q为nullptr_t也是错误的。
这里总结一下
我试图比较这发生在 C 中和发生在 C++ 中,我觉得这些事情是相互矛盾的
但实际上在 C 中我使用 %f 来打印第一个错误的指针地址。在 C++ 代码中,我认为一切都很好,除了一件事是假设空指针指向第一个内存块是错误的,因为它没有在 c 标准中指定它只是说 nullptr 常量在评估时与 0 比较。
问题太多了,所以这不是正确的问题
[更新结束]
解决方法
printf("%f\n",q);
格式说明符 %f 要求传递的对象的类型为 double
类型(float
参数将被隐式转换,因此也可以)。您传递了错误类型的 float*
。将错误类型的参数传递给 printf
会导致未定义的行为。
printf("%p",q);
这个有点微妙,但是 %p 说明符要求参数的类型为 void*
。 float*
仍然是错误的类型,因此行为仍未定义。
您应该更加小心地使用正确的格式说明符和参数类型。 C 格式的 I/O API 非常无情。
在 C++ 中给出输出 0
请注意,输出是 0 还是其他取决于系统使用什么值来表示空指针。
为什么在 C++ nullptr 中将其类型从 nullptr_t 更改为浮点类型
nullptr
在您的示例中从未“将其类型更改为浮点类型”。在 float *q=nullptr
中,隐式转换为类型 float*
。
但在 C 中 NULL 并没有将它的类型从 (void ) 更改为 (float) ?
NULL
宏的类型不是 C 中的 void
。它可以是整数常量 0,或者这样的常量转换为 void*
。这两者都可以隐式转换为任何指针类型。这就是 float *q=NULL
中发生的事情。
因此,在两种语言中,您都将 null 隐式转换为指针类型。
无论哪些类型可以隐式转换为哪些类型,可变参数都不会隐式转换为格式字符串所需的类型,因为编译器不知道这些类型1 2。
1 有我提到的从 float 到 double 的转换,但这些不依赖于格式说明符。
2 如果格式字符串是常量,一些编译器确实有助于诊断您的错误,但他们不需要这样做。
,指针没有改变类型。在 cout 版本中,您让系统自然打印指针值。在 printf 版本中,您强制使用 %f。将格式字符串更改为 %ld,您将得到不同的结果。
printf 对您作为参数传递的内容一无所知。它相信程序员知道他在做什么。
---在此处编辑以回答更多问题---
您说得对,%lu 可能比 %ld 更好。我想您可能有一个设置了最高有效位的地址(这意味着 %ld 会认为它是负数)。
是:
float * q = nullptr;
表示 q
全为零。
Cout 知道正在打印什么并且(通常)做正确的事情。除非您非常特别地控制它,否则很少使用格式说明符(例如打印浮点数和双精度数时使用的位数)。我用它来设置 bool 的默认输出以打印 true
或 false
而不是 1
或 0
。但一般来说,使用 cout 时您可以获得合理的值,而无需任何额外的工作或认为必要。