为什么printf和std :: cout的输出不同?

时间:2019-03-14 11:19:30

标签: c++

我尝试了以下C ++代码。但是,printfstd::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
}

3 个答案:

答案 0 :(得分:77)

printf("%d\n", &Foo::c):这是未定义的行为,因为&Foo::c不是整数,而是指向成员的指针(但实际上,编译器通常将指向数据成员的指针存储为偏移量,并且因为8Foo::c的偏移量,所以会打印8

std::cout << &Foo::c:这将打印值&Foo::c。由于iostream没有指向成员打印机的指针,因此它选择最接近的成员:将其转换为bool并将其打印为整数。将&Foo::c转换为bool时,将打印true

答案 1 :(得分:21)

输出不同,因为printf的行为未定义。

指向成员的指针(如从&Foo::c产生的指针)不是整数。 printf函数需要一个整数,因为您也使用%d说明符告诉了它。

您可以通过向bool添加类型转换来修改它,如下所示:

printf("%d\n", (bool)&Foo::c)

指向成员的指针可能会转换为布尔值(您可以使用强制转换),然后bool会由于对a的一个完整的可变参数而经历一个int的整数提升。可变函数。

说到bool的转换,正是通过尝试调用std::ostream的{​​{1}}隐式应用的转换。由于不存在支持成员指针的运算符的重载,因此重载解析会选择将operator<<隐式转换为布尔值后可以调用的另一个。

答案 2 :(得分:5)

除了关于编译器为何以这种方式解释代码的更直截了当的答案之外:您似乎还an XY problem试图将成员指针的格式设置为整数,这强烈建议你打算做些不同的事情。

如果您想要的是存储在int中的.c值,则需要创建一个实例Foo some_foo;并接受some_foo.c,否则需要声明{ {1}}是一个Foo::c成员,因此整个课程中只有一个明确的static。在这种情况下,请勿使用地址。

如果您想要获取某个Foo::c的{​​{1}}成员的地址,则应按照上述步骤进行操作,以使.cFoo并引用一个特定变量,或者声明一个实例并使用其Foo::c成员,然后使用地址。对象指针的正确static指定符是.c,并且要打印带有printf()的对象指针表示形式,请将其转换为%p

<iostream>

如果想要的是类void*printf( "%p\n", &some_foo.c ); std::cout << static_cast<void*>{&some_foo.c} << '\n'; 的偏移量,则需要Foo::c中的Foo宏。由于它的返回值是offsetof(),在64位平台上的返回值与<stddef.h>的大小不同,因此您可能想显式地强制转换结果或将size_t传递给{{1} }类型说明符:

int

无论您想做什么,如果编译器没有警告您类型不匹配,您都应该打开更多警告。对于经过反复试验直到程序编译的人尤其如此。