Main Content

MISRA C:2012 Dir 4.9

A function should be used in preference to a function-like macro where they are interchangeable

Description

Directive Definition

A function should be used in preference to a function-like macro where they are interchangeable1 .

Rationale

When feasible, use functions instead of macros. Functions perform argument type checking and evaluate their arguments only once, avoiding problems with potential multiple side effects.

Polyspace Implementation

Polyspace® reports a violation of this rule if a macro is used at least once in the code and the macro can be replaced by a function. Polyspace assumes a macro cannot be replaced by a function if any these conditions are true:

  • The macro defines a function or a creates a call to a function using concatenation. For example, the macro MYFUNC allows inline creation of new functions using the macro parameter name. Polyspace assumes that MyFunc cannot be replaced by a function and does not report a violation.

    //Noncompliant
    #define DH(x) do { printf("using variable = %d\n", x);} while(0)
    //Compliant
    #define MYFUNC(name) void myFunc_##name(){printf("call to function\n");}
    The macro DH does not define a function or create calls to a function. Polyspace assumes that this macro can be replaced by a function and reports a violation.

  • The macro breaks control flow using the keywords return, goto, label. Use of the keyword break, or the keyword continue outside a switch block or a loop also indicates that a macro cannot be replaced by a function. For example, the macro RETURN_NUM returns a value. The macro CASES contains the break identifier outside a switch or a loop statement. Polyspace assumes that these macros cannot be replaced by a function.

    #define RETURN_NUM(x) do { \
        an_uint32 += x; \
        return 10; \
    } while(0)
    #define CASES_(x) \
        case 0: \
            printf("0\n"); \
            break; \
        case 1: \
            printf("1\n"); \
            break; \
        default: \
            printf("default\n");

  • The macro declares at least one variable that is not used within the macro. For example, the macro DECLARE_AND_INITIALIZE_VAR declares and initializes three integers. Polyspace assumes that this macro cannot be replaced by a function.

    #define DECLARE_AND_INITIALIZE_VAR(x, y, z) \
      int8_t x = 1; \
      int8_t y = x + 1; \
      int8_t z = y + 1;

  • The macro uses one of these symbols and keywords: #, __LINE__, __FILE__, and _Generic.

  • At least one of the macro parameters is used as a type in the body of the macro. For example, the macros DECLARATION and CONVERSION each use one of their parameters as a type within its body. Polyspace assumes that these macros cannot be replaced by functions.

    #define DECLARATION(x, T) do { \
        const T y = x; \
        an_uint32 += y; \
    } while(0)
        
    #define CONVERSION(x, T) ((T) (x)) 

  • At least one of the macro parameters is an operator or an expression. For example, the macro OPERATION takes an operator as an input. The macro STATEMENT takes an expression as an input. Polyspace assumes that these macros cannot be replaced by a function.

    #define OPERATION(x, y, op) ((x) op (y))
    #define STATEMENT(x, action) \
        if (!x) action

  • The macro is used for initializing a global or static variable. A function call is not permitted for this purpose.

Troubleshooting

If you expect a rule violation but do not see it, refer to Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

In this example, the function-like macro MAX evaluates its arguments multiple times. After invoking this macro, the values of x and y are 6 and 12, respectively, which is unexpected. Polyspace reports a violation on the function-like macro

#include <stdio.h>

#define MAX(a, b) ((a) > (b) ? (a) : (b))  //Noncompliant

int main() {
	int x = 5;
	int y = 10;
	int max = MAX(x++, y++);

	printf("max: %d\n", max);
	printf("x: %d\n", x);
	printf("y: %d\n", y);
	return 0;
}

Check Information

Group: Code design
Category: Advisory
AGC Category: Advisory

Version History

Introduced in R2014b

expand all


1 All MISRA coding rules and directives are © Copyright The MISRA Consortium Limited 2021.

The MISRA coding standards referenced in the Polyspace Bug Finder™ documentation are from the following MISRA standards:

  • MISRA C:2004

  • MISRA C:2012

  • MISRA C:2023

  • MISRA C++:2008

  • MISRA C++:2023

MISRA and MISRA C are registered trademarks of The MISRA Consortium Limited 2021.