More about ELESOFTROM Company

ELESOFTROM Company is specializing in firmware development and fixing for embedded systems.

We have more than 10-years of experience in that area.

In developed tasks and projects we value reliability and effectivness of the firmware.

Fixing the Software for Emebedded Systems

Software for Microcontrollers

Home page

Full offer


About company


DioneOS - RTOS for embedded devices

ELESOFTROM developed RTOS for ARM Cortex-M3 and msp430.

The system is optimized for short execution time, having short switching time between threads.
The system provides elements (e.g. semaphores, mutexes, timers, queues etc.) used for building multi-threaded firmware.

Cortex version has full tests coverage and was tested by automatic testing framework.

Read more:

DioneOS home page



DioneOS documentation

Tutorials about DioneOS

Details of Preprocessor (GNU Preprocessor)

2014-12-17    Piotr Romaniuk, Ph.D.


Macros Arguments
Sequence of Transformation
Preprocesor - Basic Information (another page)
Preprocesor - Advanced Usage (another page)

Macros Arguments

Following rules are applied to arguments of macros:

  • Arguments are separated by comma.
  • Argumnet list is specified in parenthesis (rounded brackets).
  • Number of opening and closing brackets must be balanced.
  • Number of specified arguments in usage location must be consistent with definition (special case is variable number of arguments).
  • If the argument contains a comma then it must be surrounded by parethesis, so it will be not interpretted as arguments separator.
  • Argument can be empty (i.e. not specified).
// Macro with arguments
#define SOME_MACRO( x, y, z) x+y+z

// Macro with variable number of arguments (variadic macro)
#define VAR_ARGS_MACRO(fun,...)  fun( __VA_ARGS__ )

// Example of using the macro with unspecified argument
#define CALL_FN( fun, arg1 ) fun( arg1 )
CALL_FN( send_char, mychar );  => send_char(mychar);
DEV_CTX( get_char,);           => get_char();

// Example of macro with a comma that is not arguments separator but is a part of argument:
#define DBG( level, msg_args ) do{\
					printf( "<%d> ", level);\
					printf msg_args;\
DBG( MSG_CRITICAL, ("%s %d", txt, nr) );

// Definition and usage of the macro with argument that contains a comma:
#define CRIT_ENVELOPE( call ) do{ sys_disable_irq();\
CRIT_ENVELOPE( get_scheduler_state( &context, &result ) );

Two latter examples illustrates how to write multiline macro definition. It makes macro definition more clear, easy to read and understand. Nevertheless it has no influence on macro expansion - the expansion is always in one line. If you browse intermediate file that is preprocessing output:

#61 "test.c"
 do{ sys_disable_irq(); get_scheduler_state( &context, &result ); sys_enable_irq();}while[0];

Do-while(0) envelope should be explained. The purpose of that is to force semicolon after macro usage in source code. (it will be discussed in separated description)

Please note, that arguments that appear in strings in macro body are not expanded.

#define SOME_MACRO(x) x, "x"

//above macro will be expanded to:
SOME_MACRO( 123 )	=>  123, "x"

If contents of the argument is needed as a string it should be stringified (see stringification operator).

Sequence of Transformation

When the preprocessor finds the macro usage that must be expanded it does following operations:

  • performs prescan and expands all arguments,
  • after substitution of arguments it scans the result again and expands other macros that appeared or are present there
  • arguments are not expanded if they will be stringified or concatenated
  • the preprocessor avoids recursion - the name of the macro is not expanded if it appears in macro expansion
#define GET_CHAR_RETTYPE void
#define GET_CHAR_FN      get_char

#define get_char_void sys_get_char(&gctx)

#define GET( fn, rtype ) fn ## _ ## rtype

//will be expanded to:

In order to have expansion of arguments as well, another macro must be added:

#define _GET( fn, rtype ) fn ## _ ## rtype
#define GET( fn, rtype ) _GET( fn, rtype )

//it will be expanded to:

Below is an example of recursion and the preprocessor behavior::

#define RECUR( x ) RECUR( x+2 )

// expansion with recursion is macro body:
RECUR( a ) 		=>      RECUR( a+2 )

// and in argument:
RECUR( RECUR( a ) ) 	=>	RECUR( RECUR( a+2 )+2 )


Spaces are not tokens for preprocessor but rather separators, it means that they are merged together and eliminated.

#define M( x, y ) fun(x,y)

//each following usage:
M( 1,2)
M(1, 2)
M(1,2 )
M( 1 , 2 )
M (1,2)
//will be expanded to the same result:

Spaces in argument list in macro definition are threated similar way:

//these two definitions:
#define MM_1(x,y) fun(x,y)
#define MM_2( x, y ) fun(x,y)

// are expanded to the same result:

The difference is macro body, spaces from there are copied as they appear (multiple spaces are merged in one), unless they are close to concatenation operator (they are dropped):

#define MM(x,y) fun(  x , y)
MM(1,2) 	=> 	fun( 1 , 2)

#define MCON(x,y) fun( x ## y )
MCON(a,b) 	=>	fun( ab )

The last but not least the note about spaces (consider it to be VERY IMPORTANT) in macro definition located between the macro name and argument list (exactly before opening bracket). When the space is put there it changes the type of the macro. It is recognized as object-like macro, argument-less one. Following argument list becomes a part of macro body, hence arguments are not substituted but appears as text like in definition.

// Example of macro with extra space after name (this is an error) - it is interpretted as argument-less
// parethesis is a part of macro body
#define MACRO1 (x, y) x+y   

//above macro is expanded to:
 (x, y) x+y(1,2)


  1. Preprocesor C Documentation (gcc/GNU site)
  2. Macrodefinition Description (gcc/GNU site)
  3. Arguments Description
  4. Sequence of Transformation