Warning (Anachronism): Assigning void(*)(int) to e

2019-07-14 06:27发布

问题:

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);
};

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

      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;
}

回答1:

You may change SignalHandler::NullHandler to a regular C function (let's name it SignalHandler_NullHandler). Then wrap both SignalHandler_NullHandler and SignalHandlerFn in extern „C”.

BTW. It was my guess how to „align” these two functions but you have explained it better in your comment that there is a problem with C/C++ casting.



回答2:

In the expression:

pfn ? pfn : &SignalHandler::NullHandler

the second and third operands have different types (since one points to a function with "C" language linkage, and one points to a function with "C++" language linkage); and there is no implicit conversion that changes the language linkage.

So that expression is ill-formed. Another answer suggests using casts, however that may suppress a diagnostic at the expense of silent undefined behaviour at runtime: calling a function through a pointer to function of different type.

It's possible that particular compilers provide extensions to define behaviour in any scenario that is undefined by the C++ Standard, of course. (Or happen to "work anyway").

My recommendation would be to replace SignalHandler::NullHandler with a function that has C language linkage. This can't be a class member because the language grammar precludes extern "C" from appearing inside a class definition.