Search code examples
c++visual-c++clang++reinterpret-caststatic-cast

Print an address of function in C++, g++/clang++ vs vc++ , who is right?


Consider following simple program:

#include <iostream>
void foo() { }
int main() {
    std::cout<<static_cast<void*>(foo);
}

It compiles fine on VC++ but g++ & clang++ gives compilation errors.

See live demo here ( VC++ )

See live demo here ( clang++ )

See live demo here ( g++ )

Diagnostics given by g++ & clang++:

source_file.cpp: In function ‘int main()’:
source_file.cpp:4:38: error: invalid static_cast from type ‘void()’ to type ‘void*’
     std::cout<<static_cast<void*>(foo);
                                  ^

So, the question is which compiler is right here according to C++ standard ? I think behaviour of g++ & clang++ is correct here. I know that I should use reinterpret_cast here instead of static_cast. Is this bug in VC++ compiler ? If answer depends on the specific standard of C++ then also I am curious to know about it.


Solution

  • GCC and Clang are correct, because the conversion you are attempting to perform is not among those that can be performed by static_cast. Those conversions are enumerated in [expr.static.cast]. I will briefly summarize them with references to paragraphs in that section:

    • Base to derived reference conversion (p2)
    • Conversion to xvalue of reference-compatible type (p3)
    • Conversion using the operand for direct-initialization (p4)
    • Conversion to void (p6)
    • Inverse of standard conversion sequence (p7)
    • Integer/enum conversions (p9, p10)
    • Base to derived pointer conversion (p11)
    • Derived to base pointer-to-member conversion (p12)
    • Void pointer to object pointer conversion (p13)

    Furthermore, p5 says:

    No other conversion shall be performed explicitly using a static_cast.

    The conversion of a function or function pointer to void* is not among the conversions listed.

    In particular, direct-initialization does not apply since there is no standard conversion from function pointer to void*. According to [conv.ptr]/2:

    A prvalue of type “pointer to cv T,” where T is an object type, can be converted to a prvalue of type “pointer to cv void”. The result of converting a non-null pointer value of a pointer to object type to a “pointer to cv void” represents the address of the same byte in memory as the original pointer value. The null pointer value is converted to the null pointer value of the destination type.

    Note that this only covers object pointers, not function pointers.