简体   繁体   English

C ++是否会从声明中删除'extern“C”'?

[英]Does a C++ cast strip the 'extern “C”' from a declaration?

This question is related to Warning (Anachronism): Assigning void(*)(int) to extern "C" void(*)(int) . 这个问题与Warning(Anachronism)有关:将void(*)(int) extern "C" void(*)(int) In the cited question, we had a function pointer typedef declared as extern "C" : 在引用的问题中,我们有一个函数指针typedef声明为extern "C"

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

When we attempted to assign it: 当我们尝试分配它时:

new_handler.sa_handler = (pfn ? reinterpret_cast<SignalHandlerFn>(pfn) :
                                reinterpret_cast<SignalHandlerFn>(defaultHandler));

It resulted in the error (the line numbers are a bit off, but the line above produces it): 它导致错误(行号有点偏,但上面的行产生它):

/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.

The best I can tell, the extern "C" was discarded when using the reinterpret_cast . 我能说的最好,使用reinterpret_cast时, extern "C"被丢弃了。 However, a C cast worked as expected. 然而,C演员按预期工作。

I believe Sun Studio 12.4 (SunCC 5.13) uses C++03 by defult. 我相信Sun Studio 12.4(SunCC 5.13)使用C ++ 03作为defult。 But my question applies to both C++03 and C++11 since we see a lot of both at the moment due to the popularity of GCC 4.8 and 4.9. 但我的问题同时适用于C ++ 03和C ++ 11,因为由于GCC 4.8和4.9的普及,我们目前看到了很多这两个问题。

Does a C++ cast strip the extern "C" from a declaration? 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;
}

A reinterpret_cast<T> either produces an expression of type T , or is ill-formed due to no allowable conversion existing. reinterpret_cast<T>要么生成类型为T的表达式,要么由于不存在允许的转换而形成错误。 (ref: [expr.reinterpret.cast]/1). (参考:[expr.reinterpret.cast] / 1)。

The language linkage is part of the type (ref: [dcl.link]/1). 语言链接是类型的一部分(ref:[dcl.link] / 1)。

So the result of reinterpret_cast<SignalHandlerFn> is either ill-formed, or a pointer to function with C language linkage. 因此, reinterpret_cast<SignalHandlerFn>的结果要么是reinterpret_cast<SignalHandlerFn> ,要么是指向C语言链接的函数的指针。

Accordingly, it doesn't seem correct to describe this cast as "stripping extern C" -- although of course a compiler may react to ill-formed code by issuing a diagnostic, and then proceeding as if the code had some arbitrary behaviour. 因此,将此转换描述为“剥离外部C”似乎是不正确的 - 尽管编译器当然可以通过发出诊断来对不正确的代码做出反应,然后继续进行,好像代码有一些任意行为。


In your code sample, both uses of reinterpret_cast<SignalHandlerFn> are well-formed , because reinterpret_cast may convert any function pointer to any other function pointer (ref: [expr.reinterpret.cast]/6). 在您的代码示例中, reinterpret_cast<SignalHandlerFn>两种用法都是格式正确的,因为reinterpret_cast可以将任何函数指针转换为任何其他函数指针(ref:[expr.reinterpret.cast] / 6)。

However, calling SignalHandler::NullHandler through sa_handler will cause undefined behaviour (ref: ibid.). 但是,通过sa_handler调用SignalHandler::NullHandler将导致未定义的行为(ref:同上。)。 The warning produced by your compiler could be intended to warn about this case. 编译器产生的警告可能是为了警告这种情况。

The sigaction structure is defined as: sigaction结构定义为:

   struct sigaction {
       void     (*sa_handler)(int);
       void     (*sa_sigaction)(int, siginfo_t *, void *);
       sigset_t   sa_mask;
       int        sa_flags;
       void     (*sa_restorer)(void);
   };

And you use struct sigaction's void (*sa_handler)(int); 你使用struct sigaction的void(* sa_handler)(int); to get assigned from some SignalHandlerFn. 从一些SignalHandlerFn获得分配。 So, either both declarations should be within extern "C" eg 因此,要么两个声明都应该在extern "C"例如

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

and

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

Or both should be with support of C++'s name mangling, i.ee. 或者两者都应该支持C ++的名称mangling,即。 without extern "C" as: 没有extern "C"如下:

  #include <signal.h>

and

  typedef void (*SignalHandlerFn) (int);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM