How to use Macros in Programming to make code faster, efficient and compact

by Suraj Sharma   Last Updated October 09, 2019 12:05 PM

Recently I was going through some of the solutions of the best competitive programmers in the world. I found out that those people use a template while writing the programs, preferably in C++.

I have some difficulty understanding those programs because they first create there own keywords using #define and typedef. This is done to make the code more compact and faster to write.

Now there are many instructions which we repeat many times while writing code, like for() loops. So instead of writing a long instruction I can create a macro. The same can be done for other statements to make the code more compact.

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
#include<stdbool.h>

#define SC1(x)          scanf("%lld",&x)
#define SC2(x,y)        scanf("%lld%lld",&x,&y)
#define SC3(x,y,z)      scanf("%lld%lld%lld",&x,&y,&z)
#define PF1(x)          printf("%lld\n",x)
#define PF2(x,y)        printf("%lld %lld\n",x,y)
#define PF3(x,y,z)      printf("%lld %lld %lld\n",x,y,z)
#define REP(i,n)        for(long long i=0;i<(n);i++)
#define FOR(i,a,b)      for(long long i=(a);i<=(b);i++)
#define FORD(i,a,b)     for(long long i=(a);i>=(b);i--)
#define WHILE(n)        while(n--)
#define MEM(a, b)       memset(a, (b), sizeof(a))
#define ITOC(c)         ((char)(((int)'0')+c))
#define MID(s,e)        (s+(e-s)/2)
#define SZ(a)           strlen(a)
#define MOD             1000000007
#define MAX             10000000005
#define MIN             -10000000005
#define PI              3.1415926535897932384626433832795
#define TEST(x)         printf("The value of \"%s\" is: %d\n",#x,x)

const int INF = 1<<29;

typedef long long ll;
typedef unsigned long long ull;

#define FILEIO(name) \  freopen(name".in", "r", stdin); \   freopen(name".out", "w", stdout);

I am interested in how the C-Compiler processes all those macro. I do understand the constants which are defined using macros like:

#define MOD    10000000007
#define MAX    10000000005
#define MIN    -10000000005
#define PI     3.1415926535897932384626433832795

But how I can create a function macro which can reference to a instruction, like:

#define SC1(x)          scanf("%lld",&x)
#define SC2(x,y)        scanf("%lld%lld",&x,&y)
#define SC3(x,y,z)      scanf("%lld%lld%lld",&x,&y,&z)
#define PF1(x)          printf("%lld\n",x)
#define PF2(x,y)        printf("%lld %lld\n",x,y)
#define PF3(x,y,z)      printf("%lld %lld %lld\n",x,y,z)
#define REP(i,n)        for(long long i=0;i<(n);i++)
#define FOR(i,a,b)      for(long long i=(a);i<=(b);i++)
#define FORD(i,a,b)     for(long long i=(a);i>=(b);i--)
#define WHILE(n)        while(n--)
#define MEM(a, b)       memset(a, (b), sizeof(a))
#define ITOC(c)         ((char)(((int)'0')+c))
#define MID(s,e)        (s+(e-s)/2)
#define SZ(a)           strlen(a)
#define TEST(x)         printf("The value of \"%s\" is: %d\n",#x,x)

By defining macros like the above, it is possible to increase the productivity, efficiency & speed of the programmer.

Now my questions are:

  1. When I define a macro like:
#define SC1(x)          scanf("%lld",&x)

How the compiler process this macro. More generally how this instruction is being understood by the computer when compiling/running the program.

  1. There are three different kinds of macros used for referencing three different versions of the loop:
#define REP(i,n)        for(long long i=0;i<(n);i++)
#define FOR(i,a,b)      for(long long i=(a);i<=(b);i++)
#define FORD(i,a,b)     for(long long i=(a);i>=(b);i--)

In this instruction the variable value which has to be computed first is enclosed in parenthesis. What's the significance of parenthesis when writing macros?

  1. What does \ mean in the following instruction:
#define FILEIO(name) \  freopen(name".in", "r", stdin); \   freopen(name".out", "w", stdout);

I know its a broad question related to use of macros in C/C++, I really appreciate it if someone can point me to the right direction on how to interpret/understand these macro instructions whenever encountered in a source-code so that I can modify and write my own macros for faster & efficient coding.



Answers 3


Macros make code error-prone, unreadable, and difficult to maintain.
The standard recommendation from language specialists and developers is to avoid macros, and most people agree with it.

What you can do with macros is make code dense (=unreadable), so if your target is to save disk space in source files(-> see code golf), or win specific competitions, macros are helpful, but for fast and efficient, they have zero impact. Code is fast when it is well written and the compiler is good; macros are expanded by the precompiler, and don't influence this at all.
Code writing might seem faster with macros, but only until you reach a certain level of complexity, which is about one screen full.

Note that many of the macros you listed are in decades-old coding style, so it is well possible that your source is fifteen years outdated. printf for example has better recommended options since C++07.

Aganju
Aganju
October 09, 2019 11:41 AM

This is going to be a frame challenge, because I disagree with the underlying notion that the character count of your code is the most important metric for code quality, or that templates are the best way to write code faster.

Disclaimer: This is written from the perspective of a (predominantly) C# developer, but the argument I'm making is language agnostic.


I have some difficulty understanding those programs because they first create theyr own keywords using #define and typedef.

This is the exact reason why I don't like these templates. They massively detract from readability for any developer other than the dev who coined those templates. Rewriting basic language keywords to a name you like better is a subjective holy war that doesn't add any value.

On top of that, when you shorten it, you decrease configurability. E.g. the for loop is as verbose as it needs to be in order to provide the feature set that it aims to provide. If you make it less verbose, you omit part of its feature set.

The for loop is already a condensed version of a while loop that defines an external counter and uses that counter to check for its exit condition. It is as terse as it reasonably can be.


This is done to make the code more compact...

Trying to measure code quality by the amount of characters it takes to write your code is like measuring car performance by the amount of parts that went into the construction of the car.

I cannot stress this enough: readability trumps brevity every single time. KLOC (or character count) is not a valid measure of code quality. Compact code is generally bad because it makes zero difference to the compiler (no performance increase) while making things harder for the developer to understand.

That doesn't mean there's no upper limit on how long code should be or course; but trying to condense language constructs is not reasonable.

There are fringe exceptions where less readable variants of code can be more performance than their more readable counterparts; but your use cases of basic language constructs is not one of these fringe cases.


...and faster to write.

There are other ways to handle this. An IDE can already facilitate quicker code writing without you needing to redefine the language's keywords.

As a Visual Studio example, if you type for and press Tab twice, it writes everything for you:

enter image description here

With further tab completion, it allows you to quickly write the three operations (initialization, exit condition, increment condition).

So is this better? Let's see:

  • Tab completion does take some time to master to make it become muscle memory, but using templates also needs time to master (because a new developer needs to learn the templates). It'll take about the same amount of time for you to get comfortable with it.
  • Different codebases may define different templates, but when working in the IDE you get the same features regardless of which codebase you're working in.
  • At the end of the day, when using the tab completion, the resulting code has better readability since it doesn't rely on arbitrarily created template names. Rather than needing you to know the arbitrary definitions, you can read the code itself.

I'm chalking that up as a big win in terms of using IDE tools such as tab completion as opposed to arbitrarily decided definitions.


Also, as a side note:

#define SC1(x)          scanf("%lld",&x)
#define PF3(x,y,z)      printf("%lld %lld %lld\n",x,y,z)
//...

Most of these can be written as normal methods, there is no reason to use templating here. It seems like you're drifting into the territory of misusing templating to not write a simple method.


In response to your comment

I am referring to programming competitions. Can you tell me why no one in there right mind don't want such code in industry

For the same reason no one drives a racecar to do grocery shopping. A racecar is built for competition between racers and car manufacturers, but a racecar is not a useful everyday car for the vast majority of car owners.

Similarly, industry code is not written as a challenge between developers, it is written to perform a task and to be maintainable so it can adapt when necessary.

The marginal speed gains (fractions of seconds) gained from pre-templated code is offset by the decreased readability of the code which can lead to hours of wasted effort.

Additionally, the templates might work in the scenario of one developer creating a one shot codebase; but it does not stand up to multiple developers having to revisit the same codebase.

Flater
Flater
October 09, 2019 11:45 AM

By defining macros like the above, it is possible to increase the productivity, efficiency & speed of the programmer.

That is a fallacy. You wrote by yourself "I have some difficulty understanding those program" - so these macros definitely did not increase your productivity for reading and understanding the code.

But let me answer your questions directly:

When I define a macro like: #define SC1(x) scanf("%lld",&x), how the compiler process this macro?

Actually, it is not the C or C++ compiler (at least not the main part of it) which does the processing, it is a component called preprocessor which does this. In laymens terms, the preprocessor here does some text replacement before the actual compiling starts. For example, after the macro definition above, the preprocessor will replace a code line like

 SC1(foo);

by

 scanf("%lld",&foo);

and that is the code the main compiler will finally see.

Your second question was:

What's the significance of parenthesis when writing macros?

Since the preprocessor does only text processing, variables of a macro are not evaluated before the macro expansion takes place, which means parenthesis' are required to make sure the result will have the expected operator preceding. For example, without these extra parentheses, a line like

 `REP(i, 1|2)`

would be expanded to

 for(long long i=0;i< 1|2 ;i++)

which is an obfucated way of introducing an endless loop, since i< 1|2 will always evaluate to a non-zero expression, regardless of the value of i.

And to your third:

What does \ mean in the following instruction:

The #define syntax usually expects the whole macro definition to appear on the same line. To span it over several lines, it is necessary to add a backslash "\" at the end of the line. But in your example , the backslash between statements it is quite nonsensical and can probably be left out.

Doc Brown
Doc Brown
October 09, 2019 12:02 PM

Related Questions


Updated June 21, 2019 02:05 AM

Updated November 22, 2016 08:02 AM

Updated February 26, 2016 01:02 AM

Updated September 28, 2019 21:05 PM

Updated December 10, 2017 19:05 PM