0

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.

Guillaume D
  • 2,202
  • 2
  • 10
  • 37

1 Answers1

1

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.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • in my case, it allows me to use an header file containing defines values of IRQ events like `#define IRQ_ID 1`, and then map my IRQ to the generic interrupt vector table that has been geerated. `MAP(IRQ_ID){ //do something}` by overriding the default (weak) version of the ISR. it's more for quick debug purposes. indeed, generating that code would be the cleanest solution, but i wanted to know how much it could be avoided. :) – Guillaume D Oct 26 '22 at 14:26
  • 1
    @GuillaumeD I would recommend not to rely on weak linkage vector tables in safety-related applications. One of the best defensive programming practices in microcontrollers is to explicitly implement every single ISR even if you don't plan to use it. That way you can handle mysteriously activated interrupts in a safe manner - typically just by disabling an interrupt that has fired but shouldn't fire, then report the problem to your error handler. This has been considered good practice ever since the time when MCU RAM was far more shaky and prone to flip due to EMI, cosmic rays etc. – Lundin Oct 27 '22 at 06:57
  • I'm trying to add some genericity to the current design because the ISR are not the same for each customers. so a default ISR is mapped by default to each vector of the IVT, and what this default ISR does is : raising an error. then for each customer developpment, if an IRQ fires, and is not mapped yet (by overriding the weak linkage), or if an IRQ that shall not be mapped fires, it can raise an error. I don't understand why weak linkage shall be avoided in such design? – Guillaume D Oct 27 '22 at 08:18
  • @GuillaumeD As long as you handle all ISRs - even those you didn't expect to fire - then it doesn't really matter if you have weak linkage or not. But if the default ISR is something like an empty function that does nothing, then I wouldn't recommend it. As for generating different vector tables for different customers, it sounds like something that should be handled through version control, not function-like macros and manual editing. – Lundin Oct 27 '22 at 09:12