I am writing a class that works with port RS485 traffic. When opening the port, I indicate the function called when there is some data in the input buffer of the port:

struct sigaction saio; /* definition of signal action */ fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK); /* open the device to be non-blocking (read will return immediatly) */ if (fd <0) { perror(device);} sigemptyset(&saio.sa_mask); /* install the signal handler before making the device asynchronous */ saio.sa_handler = signal_handler_IO; 

If the function - the handler is described as a learning function:

 void signal_handler_IO (int status){ if (read(fd,&buf,1)){ std::cout << "I'm recieve byte\t" << std::hex << buf[0] << std::dec << std::endl; } } 

That is no problem. But if I make this function a member of a class, then compile errors occur.

 error: cannot convert 'Rs485::signal_handler_IO' from type 'void (Rs485::)(int)' to type '__sighandler_t {aka void (*)(int)}' 

I am not very strong in C ++ and do not understand what the compiler wants from me. Tell me please, how can I make a handler function a member of the class?

  • A non - static member function of a class always receives an extra argument — an object of the class for which it is called. How can the compiler know for which particular object the handler should be called? And to you, accordingly, the question is: what is it about your handler, that it needs some class object? Is he really needed? Why are you making a handler a member of a class? What goal do you want to achieve with this? - Harry
  • The only goal is to hide the functions and data inside the class - ddipp
  • Then make it a static member function, that's all. - Harry
  • I make it static, then again a compilation error: error: cannot declare member function 'static void Rs485 :: signal_handler_IO (int)' to have static linkage [-fpermissive] - ddipp
  • How exactly do you define it? For example, not so - in the class declaration, definition outside the class, but still with the word static ? (the first thing that comes to mind when looking at a mistake) - Harry

1 answer 1

First, sa_handler is of type void (*)(int) , so it will not be possible to do much.

This is either a standard function, as in C,

 void handler(int); saio.sa_handler = &handler; 

or anonymous function without free variables (starting with [] )

 saio.sa_handler = [](int sig){ /* ... */ }; 

or static member of class

 struct Saio { static void handler(int sig) { /* ... */ } }; saio.sa_handler = &Saio::handler; 

. In this case, all three can take only one argument of the int type, and no one thought about the context (the state encapsulated in the handler object).

Well, that is, all the data needed by the processor, or assumed to be global.

 std::ostream &os = std::cout; struct Saio { static void handler(int sig) { os << "Signal #" << sig << std::endl; } }; 

or in any case static at the class level (Alexandrescu writes that this is the Monostate pattern):

 class Saio { static int handlerData; static std::string moreHandlerData() { return "Hello" }; public: static void setData(int x) { handlerData = x; } static void handler(int sig) { os << moreHandlerData() << ", this is handler#" << handlerData << " speaking, I've got signal" << sig << std::endl; } }; int Saio::handlerData = 42; 
  • In a more or less serious program, it is impossible to write to stream (including using fprintf() , etc.) ( write() possible). In general, only signal safty functions can be used in the handler - avp
  • Yes, unfortunately, this is no more or less serious program. - bipll
  • Thank you very much! Made a static member of the class, it works as it should. - ddipp