3

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

I have some difficulty understanding those programs because of the fact that they first create their own macros/types using #define and typedef. This is done to make the code more compact and to be able to type faster in competitions.

Now there are many instructions which are repeated many times while writing code, like for() loops, declaring variables of type long or long long. 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++ pre-processor processes all those macros. 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 can I create a function macro which can reference to 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, right?

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 pre-processor 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 the above instructions, the variables which have to be computed first are enclosed in parenthesis (). What's the significance of parenthesis when working with 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 and 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.

8
  • 21
    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
    CommentedOct 9, 2019 at 11:27
  • 15
    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
    CommentedOct 9, 2019 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.CommentedOct 9, 2019 at 11:59
  • 7
    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
    CommentedOct 9, 2019 at 12:14
  • 1
    +1 for this question as it has stimulated an excellent and informative discussion. It is useful to think of the difference between what you might do in a coding competition vs what is needed to create solid maintainable code for a commercial product. You occasionally run into folks that don't understand the importance of readability and mistakenly think they are optimizing the code - either to make it easier to type (??) or that it will somehow run faster without really understanding the underlying machine or what the compiler does for you.CommentedOct 14, 2019 at 19:36

4 Answers 4

17

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.

5
  • To be honest, I wouldn’t compare “competitive programming” with driving a racing car.CommentedOct 9, 2019 at 20:00
  • 3
    @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
    CommentedOct 10, 2019 at 5:38
  • 1
    A racing car is faster than an ordinary car. Mr Bean's "Armchair-on-the-roof" car is a better analogy
    – Caleth
    CommentedJul 3, 2020 at 8:38
  • @Caleth: 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. Mr Bean's car is not built with competitive features in mind.
    – Flater
    CommentedJul 3, 2020 at 9:23
  • 1
    My point was the "competetive features" generally don't help with performance, or productivity, and make it harder to fix edge cases. Bean is optimising for the niche "get home without extra expense", and still fails.
    – Caleth
    CommentedJul 3, 2020 at 9:33
11

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.

5
  • 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?CommentedOct 9, 2019 at 13:04
  • @SurajSharma: I don't work for Google and have no idea why you think I do.
    – Doc Brown
    CommentedOct 9, 2019 at 15:10
  • 3
    ... 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
    CommentedOct 9, 2019 at 15:15
  • 2
    To clarify: “Cowboy coder” is not a compliment.CommentedOct 9, 2019 at 20:02
  • 3
    @gnasher729: I think the term is to some degree double-edged, which is pretty much what I tried to express with it.
    – Doc Brown
    CommentedOct 9, 2019 at 21:15
5

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).

    4

    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.

      Start asking to get answers

      Find the answer to your question by asking.

      Ask question

      Explore related questions

      See similar questions with these tags.