Main Content

Predefined macro used as an object

You use standard library macros such as assert and errno as objects

Description

This defect occurs when you use certain identifiers in a way that requires an underlying object to be present. These identifiers are defined as macros. The C Standard does not allow you to redefine them as objects. You use the identifiers in such a way that macro expansion of the identifiers cannot occur.

For instance, you refer to an external variable errno:

extern int errno;
However, errno does not occur as a variable but a macro.

The defect applies to these macros: assert, errno, math_errhandling, setjmp, va_arg, va_copy, va_end, and va_start. The checker looks for the defect only in source files (not header files).

Risk

The C11 Standard (Sec. 7.1.4) allows you to redefine most macros as objects. To access the object and not the macro in a source file, you do one of these:

  • Redeclare the identifier as an external variable or function.

  • For function-like macros, enclose the identifier name in parentheses.

If you try to use these strategies for macros that cannot be redefined as objects, an error occurs.

Fix

Do not use the identifiers in such a way that a macro expansion is suppressed.

  • Do not redeclare the identifiers as external variables or functions.

  • For function-like macros, do not enclose the macro name in parentheses.

Examples

expand all

#include<assert.h>
typedef void (*err_handler_func)(int);

extern void demo_handle_err(err_handler_func, int);

void func(int err_code) {
    extern void assert(int);   
    demo_handle_err(&(assert), err_code);
}

In this example, the assert macro is redefined as an external function. When passed as an argument to demo_handle_err, the identifier assert is enclosed in parentheses, which suppresses use of the assert macro.

Correction — Use assert as Macro

One possible correction is to directly use the assert macro from assert.h. A different implementation of the function demo_handle_err directly uses the assert macro instead of taking the address of an assert function.

#include<assert.h>
void demo_handle_err(int err_code) {
    assert(err_code == 0);                   
}

void func(int err_code) {
    demo_handle_err(err_code);          
}

Result Information

Group: Programming
Language: C | C++
Default: On for handwritten code, off for generated code
Command-Line Syntax: MACRO_USED_AS_OBJECT
Impact: Low

Version History

Introduced in R2018a