It could be argued that in many cases X-macros increase safety, because it makes easier to make sure that generated arrays are the same length for example.
However, Misra C (from 2004 reference) rules seem to have a lot of preprocessor rules that restrict the usage:
Rule 19.1 (advisory) #include statements in a file should only be preceded by other preprocessor directives or comments.
Troublesome if source table is in other file which is included to generate array for example. But this is advisory rule so it can be worked around.
Rule 19.4 (required) C macros shall only expand to a braced initializer, a constant, a string literal, a parenthesized expression, a type qualifier, a storage class specifier, or a do-while-zero construct.
Should not be issue since most X-macros are used to generate array initializers or constants.
Rule 19.6 (required) #undef shall not be used.
Makes some X-macro usage patterns impossible. Unfortunate, but doesn't outright prevent X-macros.
Rule 19.7 (advisory) A function should be used in preference to a function-like macro.
Advisory rule only.
Rule 19.12 (required) There shall be at most one occurrence of the # or ## preprocessor operators in a single macro definition.
Can be worked around using nested macros.
Rule 19.13 (advisory) The # and ## preprocessor operators should not be used.
Troublesome when generating enums for example, but again this is only advisory rule.
Rule 19.15 (required) Precautions shall be taken in order to prevent the contents of a header file being included twice.
Troublesome in some scenarios, but can be worked around.
Looking at the above, it seems that it is possible to use X-macros with Misra C code, if you are careful.
Is my conclusion correct, or is there some rule I am missing?
Using X-macros to increase type safety is in my opinion a rather weak argument. The main thing they do is to ease maintenance and eliminate problems with code repetition. But like any function-like macros, they are the last resort when everything else fails.
The proper way to ensure that arrays are of the correct lengths etc is to use static_assert
(or some hack:ish pre-C11 mechanism) that yields a compile-time error.
Addressing your concerns one at a time:
include statements in a file should only be preceded by other preprocessor directives or comments. ... Troublesome if source table is in other file which is included...
This is a sound rule and there is no reason to deviate from it. If you have a source table in another file which you #include
, then what's the problem? The rule doesn't speak of the pre-processed header file.
The main reason for the rule is to prevent people from tossing in #include
in the middle of a file somewhere. (Which is most likely caused by some left-over debug code.)
Rule 19.4 (required) C macros shall only expand to a braced initializer, a constant, a string literal, a parenthesized expression, a type qualifier, a storage class specifier, or a do-while-zero construct.
If interpreted as the (recursively) expanded macros, it shouldn't be a problem, since X macros should boil down to constants, types etc in the end. The rule says "expand" so my take is that it refers to the fully expanded macros.
This rule has been dropped entirely in MISRA-C:2012 and replaced with other more specific rules, such as not making macros with the same name as a language keyword etc.
Rule 19.6 (required) #undef shall not be used.
This rule has been relaxed in MISRA-C:2012, from required to advisory. One valid argument raised against the rule is indeed that #undef
is necessary for X-macros, though I can't say if this is why it was relaxed.
Mostly the rule is there to prevent code like #undef NULL
or other strange and obscure ideas some people might get.
Rule 19.7 (advisory) A function should be used in preference to a function-like macro.
In general, MISRA-C is against using function-like macros, this is an advisory rule in both MISRA-C:2004 and the current MISRA-C:2012. And for very good reasons: we all know that function-like macros in general are evil, but we also know that they are often a necessary evil.
Rule 19.12 (required) There shall be at most one occurrence of the # or ## preprocessor operators in a single macro definition.
This rule has been relaxed in MISRA-C:2012 to advisory. It might be hard to write some X macros without these two. There are a couple of valid dangers associated with them, but that's addressed by other rules. I see no conflict with X macros in MISRA-C:2012.
Rule 19.15 (required) Precautions shall be taken in order to prevent the contents of a header file being included twice.
Sound rule that enforces the use of header guards. There should be no reason to deviate from it, with or without X macros.
Conclusion:
You cannot use X macros in the previous MISRA-C:2004, but you can use them in the current MISRA-C:2012. I would strongly recommend to upgrade, since MISRA-C:2012 is a major change for the better. Various pedantic rules have been dropped, relaxed or re-written. Complicated rules like the ones regarding implicit type promotions have been significantly improved. There is now C99 support. And so on.
I have used X-macros myself with MISRA-C:2012, and as far as I remember, without the need to raise deviations from any required rules.