jww jww - 2 months ago 12
C++ Question

Warning (Anachronism): Assigning void(*)(int) to extern "C" void(*)(int)

I'm having trouble with Sun's C++ compiler. I've read Oracle's Working with Pointers to Functions [from C++]. Its a good read, and I get the impression SunCC is most compliant among all the compilers in this area (though its causing me trouble).

The test code is below, and line 24 is

new_handler.sa_handler = (pfn ? pfn : &SignalHandler::NullHandler);
. Unrolling the ternary operator shows this is the issue:
new_handler.sa_handler = pfn;
.

SunCC 5.11

$ /opt/solstudio12.2/bin/CC test.cxx
"test.cxx", line 24: Warning (Anachronism): Assigning void(*)(int) to extern "C" void(*)(int).
"test.cxx", line 58: Where: While instantiating "SignalHandler<5, 0>::SignalHandler(void(*)(int), int)".
"test.cxx", line 58: Where: Instantiated from non-template code.


SunCC 5.12

$ /opt/solarisstudio12.3/bin/CC test.cxx
"test.cxx", line 24: Warning (Anachronism): Assigning void(*)(int) to extern "C" void(*)(int).
"test.cxx", line 58: Where: While instantiating "SignalHandler<5, 0>::SignalHandler(void(*)(int), int)".
"test.cxx", line 58: Where: Instantiated from non-template code.


SunCC 5.13

$ /opt/solarisstudio12.4/bin/CC test.cxx
"test.cxx", line 24: Warning (Anachronism): Using void(*)(int) to initialize extern "C" void(*)(int).
"test.cxx", line 58: Where: While instantiating "SignalHandler<5, 0>::SignalHandler(void(*)(int), int)".
"test.cxx", line 58: Where: Instantiated from non-template code.


SunCC 5.14

$ /opt/developerstudio12.5/bin/CC test.cxx
$


Its not exactly clear to me what the problem is. Here's a similar issue on the Oracle boards, but the OP is basically told to RTFM: Sun Studio 11 "Warning (Anachronism)".

How do I resolve the anachronistic warning?




solaris:~$ cat test.cxx
#include <signal.h>

// extern "C" {
typedef void (*SignalHandlerFn) (int);
// };

// S = signal number, O = overwrite
template <int S, bool O=false>
struct SignalHandler
{
SignalHandler(SignalHandlerFn pfn = NULL, int flags = 0) : m_installed(false)
{
struct sigaction new_handler;

do
{
int ret = 0;

ret = sigaction (S, 0, &m_old);
if (ret != 0) break; // Failed

// Don't step on another's handler if Overwrite=false
if (m_old.sa_handler != 0 && !O) break;

new_handler.sa_handler = (pfn ? pfn : &SignalHandler::NullHandler);
new_handler.sa_flags = (pfn ? flags : 0);

ret = sigemptyset (&new_handler.sa_mask);
if (ret != 0) break; // Failed

ret = sigaction (S, &new_handler, 0);
if (ret != 0) break; // Failed

m_installed = true;

} while(0);
}

~SignalHandler()
{
if (m_installed)
sigaction (S, &m_old, 0);
}

private:
struct sigaction m_old;
bool m_installed;

static void NullHandler(int /*unused*/) { /* continue*/ }

private:
// Not copyable
SignalHandler(const SignalHandler &);
void operator=(const SignalHandler &);
};

int main(int argc, char* argv[])
{
SignalHandler<SIGTRAP, 0> handler;
return 0;
}





If I change to the following, then all the compilers (5.11 though 5.14) produce an error:

extern "C" {
typedef void (*SignalHandlerFn) (int);
};


The error is:

$ /opt/solarisstudio12.4/bin/CC test.cxx
"test.cxx", line 24: Error: Different types for "?:" (extern "C" void(*)(int) and void(*)(int)).
"test.cxx", line 58: Where: While instantiating "SignalHandler<5, 0>::SignalHandler(extern "C" void(*)(int), int)".
"test.cxx", line 58: Where: Instantiated from non-template code.
1 Error(s) detected.


I understand why the above error occurs, and Oracle details it in its article.




I've also tried wrapping the include in
extern "C"
:

extern "C" {
# include <signal.h>
}


And casting from a
void*
:

SignalHandler(void* pfn = NULL, int flags = 0)
...
new_handler.sa_handler = reinterpret_cast<SignalHandlerFn>(pfn);

Answer

You have two problems. First, both &SignalHandler::NullHandler and the result of the ternary operator needs to be cast to SignalHandlerFn. Second, You must use C casts, and not C++ casts.

Here's what it should look like:

new_handler.sa_handler = (SignalHandlerFn)(pfn ? pfn : (SignalHandlerFn)&SignalHandler::NullHandler);
new_handler.sa_flags = (pfn ? flags : 0);
Comments