Question

I have a utility struct defined in a library API, that has four fields, all numeric counters.

typedef struct {
  size_t bytes;
  int    codepoints;
  int    graphemes;
  int    columns;
} TickitStringPos;

I want to provide some utilities to easily work on these structures. I could implement these as (static inline) functions, such as

static inline void tickit_stringpos_zero(TickitStringPos *pos) {
  pos->bytes = pos->codepoints = pos->graphemes = pos->columns = 0;
}

static inline void tickit_stringpos_limit_columns(TickitStringPos *pos, int columns) {
  pos->bytes = pos->codepoints = pos->graphemes = -1;
  pos->columns = columns;
}

TickitStringPos here, limit;
tickit_stringpos_zero(&here);
tickit_stringpos_limit_columns(&limit, 20);

Or I could implement these as macros, such as

#define TICKIT_STRINGPOS_ZERO(pos) do { \
  (pos).bytes = (pos).codepoints = (pos).graphemes = (pos).columns = 0; \
} while(0);

#define TICKIT_STRINGPOS_LIMIT_COLUMNS(pos,_columns) do { \
  (pos).bytes = (pos).codepoints = (pos).graphemes = -1; \
  (pos).columns = _columns; \
} while(0);

TickitStringPos here, limit;
TICKIT_STRINGPOS_ZERO(here);
TICKIT_STRINGPOS_LIMIT_COLUMNS(limit, 20);

What should I consider weighing up these two approaches? Each are likely to be as powerful and flexible, but is one approach specifically preferable for some reason?

Was it helpful?

Solution

Prefer functions over macro for the simple reason that they provide you type safety unlike macros.
Also, with functions you don't have to take care of any side effects unlike macros.

As for the function being inline it is just an indication to the compiler of your wish it is not binding on the compiler to make the function inline, however any modern compiler will easily do the needful.

OTHER TIPS

As Als said, I believe functions should be used when there is such a possibility, for maintanence reasons.Since they are inline, there is no performance loss.Save macros for constants, or maybe (extremely) small computations.

(note: the inline keyword makes a function be replaced in place, saving the context switching overhead but introducing space concerns.Unless you want to give space for speed, you can also use regular functions)

Macros are evaluated out of (before) the compiler scope and this is the main argument against those (being the second one that most of the times they're just unnecessary). You can find a good explanation by Bjarne Stroustrup himself here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top