Search code examples
cstatic-analysismisra

Misra C and prototype C macro generation


Will this kind of construct would need a deviation from MISRA C 2012, and 2020?

#include <stdio.h>
#define ONE 1
#define TWO 2
#define OOPS 42

#define INNER_DEF_BAR(x)  (bar_##x)
#define DEF_BAR(x) void INNER_DEF_BAR(x)(void)

DEF_BAR(ONE);
DEF_BAR(TWO);
DEF_BAR(OOPS);

DEF_BAR(ONE)
{ 
  printf("one\n");
}
DEF_BAR(TWO)
{ 
  printf("two\n");
}
DEF_BAR(OOPS)
{ 
   printf("42\n");
}

int main()
{
    bar_1();
    bar_2();
    bar_42();
    
    return 0;
}

For instance, in MISRA C 2012, I'm confused with the following sentence

Rule 20.7 Expressions resulting from the expansion of macro parameters shall be enclosed in parentheses

and the conclusion of this thread about X-macros beeing possible without deviation because breaking only advisory rules.


Solution

  • Using macros in order to declare/define functions is incredibly questionable practice in any system, particularly a critical one. This is not explicitly a (mandatory/required) MISRA violation as far as I can tell, but there is just no way code like this will pass any code review, let alone any half-decent functional safety assessor. There are few ways to aggravate code reviewers more than to invent My Little Macro Languagetm and then forcing them to learn it.

    From a strict MISRA C perspective, you are violating advisory Directive 4.9 about using function-like macros and advisory Rule 20.10 regarding use of the ## operator. It is true that you need no formal deviation for breaking advisory rules, but you still need to make an argument regarding why you are doing so. Ideally this should be on a company coding guideline level, stating which advisory rules that are ignored and which advisory rules that are enforced. That is, either you'll filter out a certain advisory rule from all static analysis, or you'll "promote it" and treat it just like any Required rule.

    X macros and function-like macros are questionable in general, but you can use them in a structured "de facto standard" way. It's possible to make an argument why they would improve code under specific scenarios.

    I sincerely doubt that you can make a sound argument for why function name generation should be done with function-like macros in a critical program though. Such a program must be deterministic with no surprises hidden behind macros. In particular there should be no type-generic or "template" programming allowed. So IMO there are only two proper solutions:

    • Remove the macros and just type out/hardcode everything, or
    • Remove the macros and pre-generate the source code using a script that runs before compilation and static analysis.

    Anything else is highly questionable.