Home > Back-end >  what this syntax in libev C language?
what this syntax in libev C language?

Time:01-09

While reading the doc in libev I find some C code of which the syntax is quite weird.

static void
stdin_cb (EV_P_ ev_io *w, int revents)
{
     puts ("stdin ready");
     // for one-shot events, one must manually stop the watcher
     // with its corresponding stop function.
     ev_io_stop (EV_A_ w);

     // this causes all nested ev_run's to stop iterating
     ev_break (EV_A_ EVBREAK_ALL);
}

I'm not sure what the EV_P_ is here, could anyone help explain it to me?

I have tried to google the syntax of method signature in C but no good matches.

CodePudding user response:

EV_P_ is a macro which means "an ev loop as a parameter, plus a comma".

EV_A_ is a macro which means "an ev loop as an argument, plus a comma".

They are defined as

#define EV_P  struct ev_loop *loop  /* a loop as sole parameter in a declaration */
#define EV_P_ EV_P,                 /* a loop as first of multiple parameters */
#define EV_A  loop                  /* a loop as sole argument to a function call */
#define EV_A_ EV_A,                 /* a loop as first of multiple arguments */

or as

# define EV_P void
# define EV_P_
# define EV_A
# define EV_A_

(Some whitespace was removed so it would fit better.)

This means

static void stdin_cb( EV_P_ ev_io *w, int revents ) {
     puts( "stdin ready" );
     ev_io_stop( EV_A_ w );
     ev_break( EV_A_ EVBREAK_ALL );
}

is equivalent to

static void stdin_cb( struct ev_loop *loop, ev_io *w, int revents ) {
     puts( "stdin ready" );
     ev_io_stop( loop, w );
     ev_break( loop, EVBREAK_ALL );
}

or

static void stdin_cb( ev_io *w, int revents ) {
     puts( "stdin ready" );
     ev_io_stop( w );
     ev_break( EVBREAK_ALL );
}

Which set of #define directives is used is configurable.

If EV_MULTIPLICITY is set and nonzero, the first set is used. The first set allows multiple ev loops to be used in the same program. (Perhaps in different threads.)

If EV_MULTIPLICITY is unset or zero, the second set is used. The second is more efficient since it uses global variables instead of passing a structure to every ev-related function. But the program can only have one event loop.

CodePudding user response:

See ev.h:

#if EV_MULTIPLICITY
struct ev_loop;
# define EV_P  struct ev_loop *loop /* a loop as sole parameter in a declaration */
# define EV_P_ EV_P,                /* a loop as first of multiple parameters */
...
#else
# define EV_P void
# define EV_P_
...
#endif

Therefore the line

stdin_cb (EV_P_ ev_io *w, int revents)

expands to

stdin_cb (struct ev_loop *loop, ev_io *w, int revents)

or

stdin_cb (ev_io *w, int revents)

depending on the value of EV_MULTIPLICITY

As pointed out by @Shawn, there is a Macro magic section that explains it:

EV_P, EV_P_

This provides the loop parameter for functions, if one is required ("ev loop parameter"). The EV_P form is used when this is the sole parameter, EV_P_ is used when other parameters are following. Example:

   // this is how ev_unref is being declared
   static void ev_unref (EV_P);

   // this is how you can declare your typical callback
   static void cb (EV_P_ ev_timer *w, int revents)

It declares a parameter loop of type struct ev_loop *, quite suitable for use with EV_A.
  • Related