Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop macro expansion of bool

Implementing functions through macros is a nightmare with bool. I've defined macros for the head and body of a (generic) function. When using bool type, results are weird.

I get that this is the kind of stuff you generally want to avoid for maintainability ~ but in my case it's a collection of really similar callback functions and a really harsh abbreviation.

So the goals are actually maintainability and readability, especially code coherence.

#include <stdio.h>
#include <stdbool.h>

#define FUN_H(TYPE) \
  void fun_##TYPE( void )

#define FUN(TYPE) \
  FUN_H(TYPE) { \
    printf("Type is " #TYPE ".\n"); \
  }

FUN_H(int);
FUN_H(bool);

FUN(int);
FUN(bool);

int main(void) {
  fun_int();
  fun_bool();
}

Reading the code, I would expect the output "Type is int." and "Type is bool."

Actually, to make the code compile (current gcc/clang) last call must be changed to fun__Bool(); and the header to FUN_H(_Bool); -- which actually makes sense if you know your C99, but produces incoherent code.


Possible solutions

Use _Bool type directly

FUN_H(_Bool);
FUN(_Bool); // or FUN(bool);

int main(void) {
  fun__Bool();
}

PROs

  • no footprint

CONs

  • ugly!
  • two ways to do define the same function, but printing different outputs

Manually expand FUN() macro

#define FUN(TYPE) \
  void fun_##TYPE( void ) { \
    printf("Type is " #TYPE ".\n"); \
  }

PROs

  • general solution for other macro'ed types

CONs

  • not DRY compliant

typedef for _Bool

typedef _Bool mybool;

FUN_H(mybool);
FUN(mybool);

int main(void) {
  fun_mybool();
}

PROs

  • conservative

CONs

  • special type name needed

Change bool into a typedef

#undef bool
typedef _Bool bool;

FUN_H(bool);
FUN(bool);

int main(void) {
  fun_bool();
}

PROs

  • clean

CONs

  • might break something arcane

So what should I do?

like image 999
miehe-dup Avatar asked Aug 12 '19 12:08

miehe-dup


Video Answer


2 Answers

It's the inner FUN_H macro call that expands bool to _Bool if bool is a macro. If you lose the inner FUN_H macro and write FUN directly like so:

#include <stdio.h>
#include <stdbool.h>

#define FUN_H(TYPE) \
  void fun_##TYPE( void )

#define FUN(TYPE) \
  void fun_##TYPE( void ) { \
    printf("Type is " #TYPE ".\n"); \
  }

FUN_H(int);
FUN_H(bool);

FUN(int);
FUN(bool);

int main(void) {
  fun_int();
  fun_bool();
}

then you'll get fun_bool as expected, even if bool is a macro.

like image 70
PSkocik Avatar answered Sep 23 '22 01:09

PSkocik


As mentioned, passing TYPE to any intermediate macro will force its expansion before further processing. So the concatenation must happen as early as possible, before passing TYPE anywhere. To achieve it without repeating ourselves too much, we can just delegate to a third macro

#define FUN_H(TYPE) \
  FUN_H_(fun_##TYPE)

#define FUN_H_(NAME) \
  void NAME( void )

#define FUN(TYPE) \
  FUN_H_(fun_##TYPE) { \
    printf("Type is " #TYPE ".\n"); \
  }
like image 39
StoryTeller - Unslander Monica Avatar answered Sep 21 '22 01:09

StoryTeller - Unslander Monica