这个问题与Warning (Anachronism): Assigning void(*)(int) to extern "C" void(*)(int) 有关。在引用的问题中,我们有一个函数指针typedef声明为extern "C":

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

当我们尝试分配它时:
new_handler.sa_handler = (pfn ? reinterpret_cast<SignalHandlerFn>(pfn) :
                                reinterpret_cast<SignalHandlerFn>(defaultHandler));

导致错误(行号有些偏离,但上面的行产生了此错误):

/opt/solarisstudio12.4/bin/CC -DDEBUG -c test.cpp
...
"ossig.h", line 75: Warning (Anachronism): Using void(*)(int) to initialize extern "C" void(*)(int).
"test.cpp", line 135:     Where: While instantiating "SignalHandler<5, 0>::SignalHandler(extern "C" void(*)(int), int)".
"test.cpp", line 135:     Where: Instantiated from non-template code.
2 Warning(s) detected.

据我所知,使用extern "C"reinterpret_cast被丢弃了。但是,C强制转换按预期方式工作。

我相信Sun Studio 12.4(SunCC 5.13)使用了defult的C++ 03。但是我的问题适用于C++ 03和C++ 11,因为由于GCC 4.8和4.9的普及,目前我们看到了很多。

C++是否会从声明中剥离extern "C"
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 ? reinterpret_cast<SignalHandlerFn>(pfn) :
                                      reinterpret_cast<SignalHandlerFn>(&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;
}

最佳答案

reinterpret_cast<T>要么生成类型为T的表达式,要么由于不存在允许的转换而格式错误。 (引用:[expr.reinterpret.cast]/1)。

语言链接是该类型的一部分(引用:[dcl.link]/1)。

因此,reinterpret_cast<SignalHandlerFn>的结果要么格式不正确,要么是指向具有C语言链接功能的指针。

因此,将这种强制转换描述为“剥离外部C”似乎是不正确的-尽管当然编译器可能会通过发出诊断来对格式错误的代码使用react,然后进行处理,就好像该代码具有某些任意行为一样。

在您的代码示例中,reinterpret_cast<SignalHandlerFn>的两种用法都格式正确,因为reinterpret_cast可以将任何函数指针转换为任何其他函数指针(引用:[expr.reinterpret.cast]/6)。

但是,通过SignalHandler::NullHandler调用sa_handler将导致未定义的行为(引用:同上)。您的编译器产生的警告可能旨在警告这种情况。

关于c++ - C++是否从声明中剥离 'extern “C”'?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39584003/

10-13 08:24