3

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/C++ compiler pre-processor process all those macro's. 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.

  • 11
    You refer to "competitive" programmers. Are you talking about programming competitions? No one in their right mind would really want such things in industry code. – marstato Oct 9 at 11:27
  • @marstato Yes I am referring to programming competitions. Can you tell me why no one in there right mind don't want such code in industry as you refer to. One of the reasons which I suppose would be writing easy to understand, bug free code. – Suraj Sharma Oct 9 at 11:30
  • 9
    Code is read many times more than it is written. As you say yourself: you have quite some difficulty understanding these macros. You spent some time trying to understand them. Now you posted a question online and you'll spend more time until you've fully grasped these macros. Now you change to another codebase where the FORD macro is defined slightly differently. You'll spend even more time adapting your thinking and fixing mistakes resulting from the difference every time yout switch codebases. All that to save - like 15 keystrokes (1-2 seconds for a competent typist). Thats not worth it. – marstato Oct 9 at 11:36
  • 1
    With these being global it effectively creates a new language. When I see a code base like this I don't call it c. I call it Macroed up c. Never seen anyone glad to hear they're going to be working in it. – candied_orange Oct 9 at 11:59
  • 4
    While I disagree with the core of the question (hence my answer), I do think it is a valid question, and I disagree with the downvotes. I also don't get why this is being close voted as too broad, the question is specifically about a C++ feature and how it should(n't) be used, with practical examples and OP's understanding explicitly stated. – Flater Oct 9 at 12:14
13

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.

  • To be honest, I wouldn’t compare “competitive programming” with driving a racing car. – gnasher729 Oct 9 at 20:00
  • 2
    @gnasher729: Why is that? The analogy is sufficient for what I'm using it for, i.e. pointing out that competitive features are not the guiding standard for everyday usage. – Flater Oct 10 at 5:38
7

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. That means parentheses are required to make sure the result will behave semantically like a regular function call, where arguments are first evaluated and the result is processed inside the function.

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 has a different semantics than for(long long i=0;i< (1|2) ;i++) In fact, without the parenthesis this would be an obfuscated way of introducing an endless loop, since i< 1|2 will always evaluate to a non-zero expression, regardless of the value of i. That is because "<" has a higher operator preceeding than "|" in C and C++.

And to your third question:

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 "\" to the end of the line. But in your example, the backslash between those statements on the same line has quite no effect and can probably be left out.

  • Sir, as you work in Google as a Software Engineer and should be familiar with Competitive Programmers and code which they write, why would they use so much macros? – Suraj Sharma Oct 9 at 13:04
  • @SurajSharma: I don't work for Google and have no idea why you think I do. – Doc Brown Oct 9 at 15:10
  • 2
    ... But to your question: in competitive programming, the goal is usually not to create maintainable programs. It is often about creating a small quick-and-dirty solution, probably under time-pressure. For this restricted field, introducing such cryptic abbreviations, which is what those macros are, may sometimes be helpful for cowboy coders to save keystrokes. – Doc Brown Oct 9 at 15:15
  • To clarify: “Cowboy coder” is not a compliment. – gnasher729 Oct 9 at 20:02
  • 1
    @gnasher729: I think the term is to some degree double-edged, which is pretty much what I tried to express with it. – Doc Brown Oct 9 at 21:15
2

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.

2

Macros like these can be useful for competitive programming, where code is written, but nobody ever attempts to read or maintain the code. It's written, run to prove that it works, then (in essence) thrown away. Given the fact that the code will never be maintained, it's reasonable that you'd optimize solely for speed of initial development.

Normal code, however, is maintained, often for years. During that time, you typically end up spending (a lot) more time reading the code than actually writing it. Macros like these optimize for writing at the (extreme) expense of reading, so outside of competitive programming, they're almost certainly a net loss (and quite a large one at that).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.