信号系统调用是否可以与类的C ++静态成员一起使用?

时间:2022-09-01 15:44:57

Is the following supported across *nix platforms?

* nix平台是否支持以下内容?

    #include <cstdio>
    #include <sys/types.h>
    #include <signal.h>
    #include <unistd.h>

    class SignalProcessor
    {
     public:
      static void OnMySignal(int sig_num)
      {
          printf("Caught %d signal\n", sig_num);
          fflush(stdout);

          return;
      } 
    }; 
    using namespace std;

   int main()
   {

          signal(SIGINT,SingalProcessor::OnMySignal);
          printf("Ouch\n");

          pause();

          return 0;
   }

3 个解决方案

#1


Technically no you can't.

技术上没有你不能。

You just happen to be getting lucky that your compiler is using the same calling convention that it uses for 'C' functions. As the C++ ABI is not defined the next version of the compiler is free to use a completely different calling convention and this will mess with your code with no warning from the compiler.

你碰巧很幸运,你的编译器正在使用它用于'C'函数的相同调用约定。由于没有定义C ++ ABI,编译器的下一个版本可以*地使用完全不同的调用约定,这将使代码混乱而不会被编译器发出警告。

See: http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
See the note at the end of this section

请参阅:http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2请参阅本节末尾的注释

Note: static member functions do not require an actual object to be invoked, so pointers-to-static-member-functions are usually type-compatible with regular pointers-to-functions. However, although it probably works on most compilers, it actually would have to be an extern "C" non-member function to be correct, since "C linkage" doesn't only cover things like name mangling, but also calling conventions, which might be different between C and C++.

注意:静态成员函数不需要调用实际对象,因此指向静态成员函数的指针通常与常规指向函数类型兼容。然而,虽然它可能适用于大多数编译器,但实际上它必须是一个外部的“C”非成员函数才能正确,因为“C链接”不仅涵盖名称修改等内容,还包括调用约定,可能在C和C ++之间有所不同。

Edit:
To answer the comment by Sasha:

编辑:回答Sasha的评论:

Using threading as an example:

以线程为例:

#include <iostream>
class Thread
{    public:   virtual void run()  = 0; };

extern "C" void* startThrerad(void* data)
{
    Thread*  thread = reinterpret_cast<Thread*>(data);
    try
    {
        thread->run();
    }
    catch(...)
    {    /* Log if required. Don't let thread exit with exception. */ }
    return NULL;
}
class MyJob: public Thread
{
    public: virtual void run() {std::cout << "HI\n";}
};
int main()
{
    MyJob     job; // MyJob inherits from Thread
    pthread_t th;

    // In most situation you do not need to dynamic cast.
    // But if you use multiple inheritance then things may get
    // interesting, as such best to always use it.
    pthread_create(&th,NULL,startThrerad,dynamic_cast<Thread*>(&job));

    void*     result;
    pthread_join(th,&result);
}

#2


That should work just fine. In fact, you could expand that function to call specific instances of that class dependent on the signal caught. For example, if you add a non-static method Process to you class, you can do something like this:

这应该工作得很好。实际上,您可以扩展该函数以根据捕获的信号调用该类的特定实例。例如,如果向类添加非静态方法Process,则可以执行以下操作:

SignalProcessor* sp[MAX_SIGNALS];

static void SignalProcessor::OnMySignal(int sig_num)
{
      printf("Caught %d signal\n", sig_num);

      if (0 < sp[sig_num])
            sp[sig_num]->Process();

      fflush(stdout);

      return;

}

#3


I do the equivalent with Windows thead procedures and other assorted callbacks, and RTX interrupts all the time. The only real gotchas are that the members have to be static (which you already figured out), and that you have to make sure your routine is set to use the standard C/system call calling convention. Sadly, how you do that is platform dependent. In Win32 it is with the "__stdcall" modifier.

我使用Windows thead程序和其他各种各样的回调,并且RTX一直在中断。唯一真正的问题是成员必须是静态的(你已经想到了),并且你必须确保你的例程设置为使用标准的C /系统调用调用约定。遗憾的是,你如何做到这一点取决于平台。在Win32中,它使用“__stdcall”修饰符。

Note that you can use the passback-in pointer paramteter to "convert" such calls into normal class method calls. Like so ("self_calling_callback" is the static method):

请注意,您可以使用回传指针参数将这些调用“转换”为普通的类方法调用。像这样(“self_calling_callback”是静态方法):

unsigned long __stdcall basic_thread::self_calling_callback (void *parameter) {
   if (parameter) {
      basic_thread * thread = reinterpret_cast<basic_thread *>(parameter);
      thread->action_callback();
   }
   return 0; 
   // The value returned only matters if someone starts calling GetExitCodeThread
   // to retrieve it.
}

basic_thread::basic_thread () {
   // Start thread.
   m_Handle = CreateThread(NULL,
                           0,
                           self_calling_callback,
                           (PVOID)this,
                           0,
                           &m_ThreadId );
   if( !IsHandleValid() )
      throw StartException("CreateThread() failed", GetLastError());
}

#1


Technically no you can't.

技术上没有你不能。

You just happen to be getting lucky that your compiler is using the same calling convention that it uses for 'C' functions. As the C++ ABI is not defined the next version of the compiler is free to use a completely different calling convention and this will mess with your code with no warning from the compiler.

你碰巧很幸运,你的编译器正在使用它用于'C'函数的相同调用约定。由于没有定义C ++ ABI,编译器的下一个版本可以*地使用完全不同的调用约定,这将使代码混乱而不会被编译器发出警告。

See: http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
See the note at the end of this section

请参阅:http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2请参阅本节末尾的注释

Note: static member functions do not require an actual object to be invoked, so pointers-to-static-member-functions are usually type-compatible with regular pointers-to-functions. However, although it probably works on most compilers, it actually would have to be an extern "C" non-member function to be correct, since "C linkage" doesn't only cover things like name mangling, but also calling conventions, which might be different between C and C++.

注意:静态成员函数不需要调用实际对象,因此指向静态成员函数的指针通常与常规指向函数类型兼容。然而,虽然它可能适用于大多数编译器,但实际上它必须是一个外部的“C”非成员函数才能正确,因为“C链接”不仅涵盖名称修改等内容,还包括调用约定,可能在C和C ++之间有所不同。

Edit:
To answer the comment by Sasha:

编辑:回答Sasha的评论:

Using threading as an example:

以线程为例:

#include <iostream>
class Thread
{    public:   virtual void run()  = 0; };

extern "C" void* startThrerad(void* data)
{
    Thread*  thread = reinterpret_cast<Thread*>(data);
    try
    {
        thread->run();
    }
    catch(...)
    {    /* Log if required. Don't let thread exit with exception. */ }
    return NULL;
}
class MyJob: public Thread
{
    public: virtual void run() {std::cout << "HI\n";}
};
int main()
{
    MyJob     job; // MyJob inherits from Thread
    pthread_t th;

    // In most situation you do not need to dynamic cast.
    // But if you use multiple inheritance then things may get
    // interesting, as such best to always use it.
    pthread_create(&th,NULL,startThrerad,dynamic_cast<Thread*>(&job));

    void*     result;
    pthread_join(th,&result);
}

#2


That should work just fine. In fact, you could expand that function to call specific instances of that class dependent on the signal caught. For example, if you add a non-static method Process to you class, you can do something like this:

这应该工作得很好。实际上,您可以扩展该函数以根据捕获的信号调用该类的特定实例。例如,如果向类添加非静态方法Process,则可以执行以下操作:

SignalProcessor* sp[MAX_SIGNALS];

static void SignalProcessor::OnMySignal(int sig_num)
{
      printf("Caught %d signal\n", sig_num);

      if (0 < sp[sig_num])
            sp[sig_num]->Process();

      fflush(stdout);

      return;

}

#3


I do the equivalent with Windows thead procedures and other assorted callbacks, and RTX interrupts all the time. The only real gotchas are that the members have to be static (which you already figured out), and that you have to make sure your routine is set to use the standard C/system call calling convention. Sadly, how you do that is platform dependent. In Win32 it is with the "__stdcall" modifier.

我使用Windows thead程序和其他各种各样的回调,并且RTX一直在中断。唯一真正的问题是成员必须是静态的(你已经想到了),并且你必须确保你的例程设置为使用标准的C /系统调用调用约定。遗憾的是,你如何做到这一点取决于平台。在Win32中,它使用“__stdcall”修饰符。

Note that you can use the passback-in pointer paramteter to "convert" such calls into normal class method calls. Like so ("self_calling_callback" is the static method):

请注意,您可以使用回传指针参数将这些调用“转换”为普通的类方法调用。像这样(“self_calling_callback”是静态方法):

unsigned long __stdcall basic_thread::self_calling_callback (void *parameter) {
   if (parameter) {
      basic_thread * thread = reinterpret_cast<basic_thread *>(parameter);
      thread->action_callback();
   }
   return 0; 
   // The value returned only matters if someone starts calling GetExitCodeThread
   // to retrieve it.
}

basic_thread::basic_thread () {
   // Start thread.
   m_Handle = CreateThread(NULL,
                           0,
                           self_calling_callback,
                           (PVOID)this,
                           0,
                           &m_ThreadId );
   if( !IsHandleValid() )
      throw StartException("CreateThread() failed", GetLastError());
}