Why are the outputs of printf and std::cout different?

printf("%d\n", &Foo::c): this is undefined behavior, as &Foo::c is not an integer, but a pointer to member (but, actually, it is usual that the compiler stores pointer to data member as offset, and as 8 is the offset of Foo::c, 8 is printed).

std::cout << &Foo::c: this prints the value &Foo::c. As iostream doesn't have a pointer to member printer, it chooses the closest one: it converts it to bool, and prints it as integer. As &Foo::c converted to bool is true, 1 is printed.


The output is different because the behavior of your printf is undefined.

A pointer to member (like the one produced from &Foo::c) is not an integer. The printf function expects an integer, since you told it too with the %d specifier.

You can amend it by adding a cast to bool, like this:

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

A pointer to member may be converted to a bool (which you do with the cast), and the bool then undergoes integral promotion to an int on account of being an integral variadic argument to a variadic function.

Speaking of the conversion to bool, it's exactly the conversion that is applied implicitly by attempting to call std::ostream's operator<<. Since there isn't an overload of the operator that supports pointers to members, overload resolution selects another that is callable after implicitly converting &Foo::c to a boolean.


In addition to the more literal answer about why the compiler interpreted your code the way it did: you seem to have an XY problem You’re trying to format a pointer-to-member as an integer, which strongly suggests you meant to do something different.

If what you wanted was an int value stored in .c, you either need to create an instance Foo some_foo; and take some_foo.c, or else you need to declare Foo::c a static member, so there’s one unambiguous Foo::c across the entire class. Do not take the address in this case.

If what you wanted was to take an address of the .c member of some Foo, you should do as above so that Foo::c is static and refers to one specific variable, or else declare an instance and take its .c member, then take the address. The correct printf() specifier for an object pointer is %p, and to print an object pointer representation with <iostream>, convert it to void*:

printf( "%p\n", &some_foo.c );
std::cout << static_cast<void*>{&some_foo.c} << '\n';

If what you want is the offset of Foo::c within class Foo, you want the offsetof() macro in <stddef.h>. Since its return value is size_t, which is not the same size as int on 64-bit platforms, you would want to either cast the result explicitly or pass printf() the z type specifier:

#include <stddef.h>

/* ... */

  constexpr size_t offset_c = offsetof( Foo, c );
  printf( "%zu\n", offset_c );
  cout << offset_c << '\n';

Whatever you were trying to do, if your compiler didn’t warn you about the type mismatch, you ought to turn on more warnings. This is especially true for someone coding by trial and error until the program compiles.

Tags:

C++