Macros in C/C++ — part(2)

Siddesh G V
4 min readJul 17, 2021

This post will be in continuation to part(1) — An introduction to Macros, will be providing the link to it in the comment and reference section in case you want to read it before part -2.

In this article I will be discussing more on

  1. How to define a multiline macro and some examples to understand the same.
  2. What are predefined macros and how to use them.

Ok, with this introduction lets dive into section 1 of the article.

  1. Defining multiline Macros

Before I start with multiline macro , let me quote an example of simple/one liner macro so that it will help us in differentiating and understanding the concepts in much better way.

#define SQUARE(X) ((X) * (X))

Above example calculates the square of a number that user inputs , for example SQUARE(5) → gets replaced with (5)*(5).

In real world use case its known that complete solution to any problem cannot be written in one single line. for example if user want to write a macro which prints a maximum among given two integers, will define it as follows.

#define MAX(a,b)\

if(a > b) \

printf(“%s is greater than %s”,#a,#b); \

else \

printf(“%s is greater than %s”,#b,#a); \

Invocation → int a = 10, b = 20;

MAX(a,b);

\ → is used here to break the logic into multiple lines.

# → prints the string representation of input parameters

following is the output of the program

output -> “b is greater than a”.

Lets look at another example to understand where multiline macro can come in handy, lets consider a scenario where user wants to calculate the sum of first N integers.

#define calculate_sum(size)\

int sum = 0; \

for (int i = 0; i < size; i++) \

{ \

sum = sum + i;\

}\

printf(“sum of first %d integers = %d.”,size,sum); \

Invocation -> int N = 10;

calculate_sum(N);

output ->sum of the first 10 integers = 45.

with this understanding , lets now jump into the second section of the article.

2. What are predefined macros and how to use them .

The definition as per GNU org —

The standard predefined macros are specified by the relevant language standards, so they are available with all compilers that implement those standards. Older compilers may not provide all of them. Their names all start with double underscores.

1. __FILE__

This macro expands to the name of the current input file, in the form of a C string constant. This is the path by which the preprocessor opened the file, not the short name specified in ‘#include’ or as the input file name argument. For example, "/usr/local/include/myheader.h" is a possible expansion of this macro.

2. __LINE__

This macro expands to the current input line number, in the form of a decimal integer constant. While we call it a predefined macro, it’s a pretty strange macro, since its “definition” changes with each new line of source code.

3. __DATE__

This macro expands to a string constant that describes the date on which the preprocessor is being run. The string constant contains eleven characters and looks like "Feb 12 1996". If the day of the month is less than 10, it is padded with a space on the left. If GCC cannot determine the current date, it will emit a warning message (once per compilation) and __DATE__ will expand to "??? ?? ????".

4. __TIME__

This macro expands to a string constant that describes the time at which the preprocessor is being run. The string constant contains eight characters and looks like "23:59:01". If GCC cannot determine the current time, it will emit a warning message (once per compilation) and __TIME__ will expand to "??:??:??".

Lets see them in action with an example

int main()

{

printf(“line number = %d\n”, __LINE__);

printf(“file name = %s\n”, __FILE__);

printf(“Date format = %s\n”, __DATE__);

printf(“Time stamp format %s\n”, __TIME__);

return 0;

}

Here is the output of the program :

line number = 26
filename=C:\Users\Siddesha_G_V\source\repos\Project3\Project3\Source.cpp
Date format = Jul 17 2021
Time stamp format 22:27:35

Let us see one real world example where these predefined macros are useful.

Consider a scenario where we are asked to develop a simple logger which logs in all the debug messages to standard error, which should contain the following information.

  1. User Input Data — Example → “Hello world!”.
  2. LINE number
  3. FILE name
  4. METHOD name

These information will be helpful while debugging, incase if anything goes wrong user can easily identify the errors.

we can write a simple debug_msg_print() function for the given scenario as follows

Define one macro to enable debug logging :

#define DEBUG 1

#define debug_msg_print(fmt, ...) \do { if (DEBUG) fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, __VA_ARGS__); } while (0)

Invocation ->

int* ptr = NULL;

if(!ptr)

debug_msg_print(“NULL pointer exception will be thrown.”);

Output — C:\Users\Siddesha_G_V\source\repos\Project3\Project3\Source.cpp:37:main(): NULL pointer exception will be thrown.

Hope this article was useful, please feel free to leave comments if you find something needs to corrected.

In our next Article we will discuss about what void* pointers are, their uses cases with examples.

--

--