我尝试了以下C ++代码。然而,的输出printf
和std::cout
是不同的。为什么?
struct Foo
{
int a;
int b;
int c;
};
int main()
{
printf("%d\n", &Foo::c); // The output is 8
std::cout << &Foo::c << "\n"; // The output is 1
}
Run Code Online (Sandbox Code Playgroud)
gez*_*eza 78
printf("%d\n", &Foo::c)
:这是未定义的行为,因为&Foo::c
不是整数,而是一个指针构件(但,实际上,作为偏移编译器存储指向数据成员,通常,并且作为8
是的偏移Foo::c
,8
打印)。
std::cout << &Foo::c
:打印值&Foo::c
。由于iostream没有指向成员打印机的指针,因此它选择最接近的指针:将其转换为bool
,并将其打印为整数。由于&Foo::c
转换为bool
是true
,1
被打印出来。
Sto*_*ica 21
输出是不同的,因为您的行为printf
是不确定的。
指向成员的指针(如从产生的指针&Foo::c
)不是整数。该printf
函数需要一个整数,因为您也已在%d
说明符中告诉了它。
您可以通过向添加演员表来修改它bool
,如下所示:
printf("%d\n", (bool)&Foo::c)
Run Code Online (Sandbox Code Playgroud)
指向成员的指针可以转换为布尔型(您可以使用强制转换),bool
然后int
由于是可变参数的完整可变参数而经历了整数提升。
说到到的转换bool
,正是通过尝试调用std::ostream
的隐式应用的转换operator<<
。由于不存在支持成员指针的运算符的重载,因此重载解析会选择一个隐式转换&Foo::c
为布尔值后可以调用的运算符。
除了关于编译器为何以这种方式解释代码的更直截了当的答案之外:您似乎还有一个XY问题 您正在尝试将一个指向成员的指针格式化为整数,这强烈表明您打算做某事不同。
如果您想要的是一个int
存储在中的值.c
,则您需要创建一个实例Foo some_foo;
并接受some_foo.c
,或者您需要声明Foo::c
一个static
成员,因此Foo::c
整个类中没有一个明确的成员。在这种情况下,请勿使用该地址。
如果要获取某.c
成员的地址Foo
,则应按照上述操作进行操作,Foo::c
即static
并引用一个特定变量,或者声明一个实例并获取其.c
成员,然后获取该地址。printf()
对象指针的正确说明符是%p
,并使用来打印对象指针表示形式<iostream>
,将其转换为void*
:
printf( "%p\n", &some_foo.c );
std::cout << static_cast<void*>{&some_foo.c} << '\n';
Run Code Online (Sandbox Code Playgroud)
如果你想被偏移什么Foo::c
类中Foo
,你想要的offsetof()
宏<stddef.h>
。由于它的返回值是size_t
,这不是大小相同的int
在64位平台上,你会明确地想要么把结果或传递printf()
的z
类型说明:
#include <stddef.h>
/* ... */
constexpr size_t offset_c = offsetof( Foo, c );
printf( "%zu\n", offset_c );
cout << offset_c << '\n';
Run Code Online (Sandbox Code Playgroud)
无论您尝试做什么,如果编译器没有警告您类型不匹配,您都应该打开更多警告。对于经过反复试验直到程序编译的人来说尤其如此。
归档时间: |
|
查看次数: |
3334 次 |
最近记录: |