The preprocessor in C — exercises with lift capacity, a floor limiter and a simulator with traces (and the DEBUG 0 that switched nothing off)

After that zero for submitting an assignment full of traces, I became very disciplined: at the very top I put #define DEBUG 1 and every trace inside an #ifdef DEBUG. For the submission, I changed the 1 to a 0, convinced that this switched them off. I ran the program the night before the deadline and… there they all were, one after another. #ifdef does not ask whether it is 1 or 0: it asks whether it exists. And it did.

These exercises are so that it does not happen to you. You will write your own macros, wrestle with the preprocessor’s traps and build a small simulator with headers and traces that switch on with -DDEBUG. If you get stuck, the theory and the practice have everything you need.

How to use these exercises

  1. Read the statement and the expected output, and write your solution without looking at the solutions.
  2. Always compile with gcc -Wall -std=c11: in this topic the compiler warnings will give away more than one macro bug.
  3. If it does not work, open the 🔵 hint and, if it still does not work, look at your code with gcc -E -P to see what the preprocessor has done.
  4. When it works, compare it with the solution: what matters is understanding why it is written that way, especially the parentheses.

Level 1: The capacity calculator

Write a program with these constants: MAX_LOAD 1500, ADULT_WEIGHT 75, CHILD_WEIGHT 35 and NUM_GROUPS 4. Define two macros:

  • GROUP_WEIGHT(adults, children): the weight of the group.
  • FITS(kg): true if the lift can carry those kilos (exactly 1500 kg still fits).

The groups have {4, 15, 20, 16} adults and {2, 6, 0, 10} children. For each group, print its weight, whether it fits and, as an acid test for your parentheses, the weight and result if one more adult got in, calculated with GROUP_WEIGHT(adults[i] + 1, children[i]).

Expected output:

Group 1 ( 4+ 2):  370 kg fits      | with one more adult:  445 kg fits
Group 2 (15+ 6): 1335 kg fits      | with one more adult: 1410 kg fits
Group 3 (20+ 0): 1500 kg fits      | with one more adult: 1575 kg too big
Group 4 (16+10): 1550 kg too big   | with one more adult: 1625 kg too big

If the “with one more adult” column gives strange figures (for example, 149 instead of 445 for the first group), the + 1 is being added without being multiplied. Check the parentheses around the parameters. To line up “fits” and “too big” use %-9s, which pads with spaces on the right up to 9 characters.

Level 2: The floor limiter

The building goes from floor −2 to floor 8, but the panel buttons sometimes send impossible requests. Define the macros MIN(a, b), MAX(a, b), CLAMP(x, lo, hi) (which keeps x inside the range [lo, hi]) and ABS(x). The cabin starts on floor 0 and receives the requests {5, 12, -4, 0, 8, -2, 9}. For each one, the cabin goes to the clamped floor; mark with “(corrected)” the ones that had to be changed. At the end, count the corrected requests and the total floors travelled.

Expected output:

Request   5 -> goes to  5
Request  12 -> goes to  8 (corrected)
Request  -4 -> goes to -2 (corrected)
Request   0 -> goes to  0
Request   8 -> goes to  8
Request  -2 -> goes to -2
Request   9 -> goes to  8 (corrected)
Corrected: 3 | Floors travelled: 48

CLAMP can be written with the other two macros: first raise the value to the minimum with MAX and then lower it to the maximum with MIN. And do not pass requests[i++] to any macro: copy the value into a variable first.

Level 3: The day simulator

Now with headers. Create a lift.h, with a guard, containing MAX_LOAD 1500, AVG_WEIGHT 75, MAX_PEOPLE (calculated), the macros ABS, MIN and DIV_UP(a, b) (integer division rounding up) and a struct Group with origin, destination and people. Also create a logger.h, with a guard, that includes lift.h and defines LOG(msg, value): with -DDEBUG it prints [file:line] msg = value; without it, it does nothing.

The program simulator.c includes both .h files and simulates these five groups: {0, 6, 8}, {0, 3, 25}, {4, -1, 12}, {7, 0, 41}, {-2, 5, 3}. If a group does not fit in one go, the lift makes several trips, and between trips it goes back empty for more people. For each group, work out the trips and the floors travelled, with a LOG for each value; at the end, the totals and the fullest trip of the day.

Expected output without -DDEBUG:

Group 1:  8 ppl.  0 ->  6 | 1 trip(s),  6 floors
Group 2: 25 ppl.  0 ->  3 | 2 trip(s),  9 floors
Group 3: 12 ppl.  4 -> -1 | 1 trip(s),  5 floors
Group 4: 41 ppl.  7 ->  0 | 3 trip(s), 35 floors
Group 5:  3 ppl. -2 ->  5 | 1 trip(s),  7 floors
Total: 8 trips, 62 floors, max 20 people (1500 kg) at once

And with gcc -Wall -std=c11 -DDEBUG simulator.c -o simulator:

  [simulator.c:20] trips = 1
  [simulator.c:21] floors = 6
Group 1:  8 ppl.  0 ->  6 | 1 trip(s),  6 floors
  [simulator.c:20] trips = 2
  [simulator.c:21] floors = 9
Group 2: 25 ppl.  0 ->  3 | 2 trip(s),  9 floors
  [simulator.c:20] trips = 1
  [simulator.c:21] floors = 5
Group 3: 12 ppl.  4 -> -1 | 1 trip(s),  5 floors
  [simulator.c:20] trips = 3
  [simulator.c:21] floors = 35
Group 4: 41 ppl.  7 ->  0 | 3 trip(s), 35 floors
  [simulator.c:20] trips = 1
  [simulator.c:21] floors = 7
Group 5:  3 ppl. -2 ->  5 | 1 trip(s),  7 floors
Total: 8 trips, 62 floors, max 20 people (1500 kg) at once

DIV_UP(41, 20) has to give 3. The classic trick is to add b - 1 before dividing: (41 + 19) / 20. And if you make n trips, the lift covers the leg 2n − 1 times: n trips with people and n − 1 empty returns.

What’s wrong here?

Three snippets that compile (some with warnings) and do something different from what they seem to. Before reading the explanation, predict what they print.

Snippet 1: the ! that does not negate

#include <stdio.h>

#define MAX_LOAD 1500
#define TOO_BIG(v) v >= MAX_LOAD

int main(void) {
    int loads[] = {300, 1650, 980};
    for (int i = 0; i < 3; i++) {
        if (!TOO_BIG(loads[i]))
            printf("%d kg: can go up\n", loads[i]);
        else
            printf("%d kg: too much weight\n", loads[i]);
    }
    return 0;
}

What do you think it prints for 300, 1650 and 980 kg?

This is what really comes out:

300 kg: too much weight
1650 kg: too much weight
980 kg: too much weight

All three loads are “too much weight”, even the 300 kg one. And that is despite gcc -Wall warning us at compile time (I show the warnings without the column number):

snippet.c: In function 'main':
snippet.c:4: warning: comparison of constant '1500' with boolean expression is always false [-Wbool-compare]
snippet.c:9: note: in expansion of macro 'TOO_BIG'
snippet.c:4: warning: logical not is only applied to the left hand side of comparison [-Wlogical-not-parentheses]
snippet.c:9: note: in expansion of macro 'TOO_BIG'
snippet.c:9: note: add parentheses around left hand side expression to silence this warning

The preprocessor turns !TOO_BIG(loads[i]) into !loads[i] >= MAX_LOAD, and ! has higher precedence than >=. So C calculates (!loads[i]) >= 1500: !300 is 0 (any non-zero number negated gives 0), and 0 >= 1500 is false. The if is never true and everything goes to the else. The drawing shows both paths:

The ! that swallows the macro Top, the expected path: 300 >= 1500 is 0, and !0 is 1, can go up. Bottom, the real one: !300 is 0, 0 >= 1500 is 0, too much weight. !TOO_BIG(300) without parentheses What you think it says: !(v >= 1500) 300 >= 1500 0 !0 = 1 can go up What C understands: (!v) >= 1500 !300 0 0 >= 1500 0 too much weight The ! has higher precedence than >=: it only applies to v, and !300 is 0 for any load other than 0.
With v = 300 the bottom path always gives 0: that is why all three loads come out as “too much weight”.

Trusting that the macro “is a condition”. Without outer parentheses, any operator you put in front (a !, a -, a *) sticks only to the first part. The -Wlogical-not-parentheses and -Wbool-compare warnings are telling you exactly that.

The fix is to put the whole macro, and its parameter, in parentheses:

#include <stdio.h>

#define MAX_LOAD 1500
#define TOO_BIG(v) ((v) >= MAX_LOAD)

int main(void) {
    int loads[] = {300, 1650, 980};
    for (int i = 0; i < 3; i++) {
        if (!TOO_BIG(loads[i]))
            printf("%d kg: can go up\n", loads[i]);
        else
            printf("%d kg: too much weight\n", loads[i]);
    }
    return 0;
}

And now it works:

300 kg: can go up
1650 kg: too much weight
980 kg: can go up

When a warning says “in expansion of macro”, the bug is almost never on the if line but in the #define. Go to the line given by the first warning (line 4 here).

Snippet 2: the semicolon that sneaks in

#include <stdio.h>

#define MAX_LOAD 1500;

int main(void) {
    int load = 640;
    int spare = MAX_LOAD - load;
    printf("Free space: %d kg\n", spare);
    return 0;
}

If there are 640 kg inside, how many are free?

What comes out:

Free space: 1500 kg

1500 kg free with 640 kg inside. The compiler warning gives the clue:

snippet.c: In function 'main':
snippet.c:7: warning: statement with no effect [-Wunused-value]

The ; in the #define is part of the replacement text, so line 7 becomes int spare = 1500; - load;. That is two statements: int spare = 1500; and - load;, which calculates −640 and throws it away (“statement with no effect”). spare stays at 1500.

Ending a #define with a semicolon out of habit. Sometimes it gives a syntax error and you find out; other times, like here, it compiles and the result is wrong.

The fix is to remove the ;:

#include <stdio.h>

#define MAX_LOAD 1500

int main(void) {
    int load = 640;
    int spare = MAX_LOAD - load;
    printf("Free space: %d kg\n", spare);
    return 0;
}

Now int spare = 1500 - load; does the whole sum:

Free space: 860 kg

1500 − 640 = 860.

-Wunused-value warnings (“statement with no effect”) on a line that uses a #define are almost always an extra ; in the definition.

Snippet 3: the DEBUG that is 0

#include <stdio.h>

#define DEBUG 0     /* 0 = debugging off... are you sure? */

int main(void) {
    int load = 640;
#ifdef DEBUG
    printf("[DEBUG] load = %d\n", load);
#endif
    printf("Load: %d kg\n", load);
    return 0;
}

With DEBUG set to 0, does the trace appear?

It does:

[DEBUG] load = 640
Load: 640 kg

This is my anecdote. #define DEBUG 0 defines the symbol DEBUG, even though its value is 0. And #ifdef DEBUG only asks whether it exists, so the trace goes through to the compiler. There is not even a warning here: as far as the preprocessor is concerned, everything is correct.

Using #ifdef with a symbol whose value is 0 or 1. Either you define it and remove it (#ifdef + -DDEBUG), or you give it a value and compare it (#if DEBUG). Mixing the two ideas does not work.

The fix, if you want to keep the 0 and 1, is to ask about the value with #if:

#include <stdio.h>

#define DEBUG 0     /* 0 = off, 1 = on */

int main(void) {
    int load = 640;
#if DEBUG
    printf("[DEBUG] load = %d\n", load);
#endif
    printf("Load: %d kg\n", load);
    return 0;
}

And the trace disappears:

Load: 640 kg

With #if DEBUG, if one day you delete the #define DEBUG, the preprocessor treats it as 0 and the traces switch off by themselves. It is the safer of the two versions.

Solutions

Level 1 solution

#include <stdio.h>

#define MAX_LOAD 1500
#define ADULT_WEIGHT 75
#define CHILD_WEIGHT 35
#define NUM_GROUPS 4

/* Parentheses around each parameter: so GROUP_WEIGHT(a + 1, n) still works */
#define GROUP_WEIGHT(adults, children) ((adults) * ADULT_WEIGHT + (children) * CHILD_WEIGHT)
#define FITS(kg) ((kg) <= MAX_LOAD)    /* <= : exactly 1500 kg still fits */

int main(void) {
    int adults[NUM_GROUPS]   = {4, 15, 20, 16};
    int children[NUM_GROUPS] = {2, 6, 0, 10};

    for (int i = 0; i < NUM_GROUPS; i++) {
        int kg = GROUP_WEIGHT(adults[i], children[i]);
        int one_more = GROUP_WEIGHT(adults[i] + 1, children[i]);   /* acid test */
        printf("Group %d (%2d+%2d): %4d kg %-9s | with one more adult: %4d kg %s\n",
               i + 1, adults[i], children[i], kg, FITS(kg) ? "fits" : "too big",
               one_more, FITS(one_more) ? "fits" : "too big");
    }
    return 0;
}

Why it is written this way:

  • GROUP_WEIGHT has parentheses around (adults) and (children). With GROUP_WEIGHT(adults[i] + 1, children[i]), without them it would become adults[i] + 1 * 75 + children[i] * 35: only the extra adult would be multiplied by 75 and the first group would weigh 4 + 75 + 70 = 149 kg instead of 445. The right-hand column is what checks it.
  • The whole expression is in parentheses in case someone writes 2 * GROUP_WEIGHT(...).
  • FITS uses <= because exactly 1500 kg fits (group 3 checks it: 20 · 75 = 1500 → “fits”).
  • FITS(kg) ? "fits" : "too big" chooses the text with the ternary operator, and %-9s lines it up.

The sums, checked:

GroupWeightFits?With one more adultFits?
14 · 75 + 2 · 35 = 300 + 70 = 370Yes370 + 75 = 445Yes
215 · 75 + 6 · 35 = 1125 + 210 = 1335Yes1410Yes
320 · 75 + 0 = 1500Yes (just)1575No
416 · 75 + 10 · 35 = 1200 + 350 = 1550No1625No

Level 2 solution

#include <stdio.h>

#define MIN_FLOOR (-2)
#define MAX_FLOOR 8
#define NUM_REQUESTS 7

#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define CLAMP(x, lo, hi) MIN(MAX((x), (lo)), (hi))   /* first the floor limit, then the ceiling */
#define ABS(x) ((x) < 0 ? -(x) : (x))

int main(void) {
    int requests[NUM_REQUESTS] = {5, 12, -4, 0, 8, -2, 9};
    int current = 0, corrected = 0, travelled = 0;

    for (int i = 0; i < NUM_REQUESTS; i++) {
        int request = requests[i];          /* copy: no requests[i++] inside the macro */
        int floor = CLAMP(request, MIN_FLOOR, MAX_FLOOR);
        if (floor != request)
            corrected++;
        travelled += ABS(floor - current);   /* floors the cabin moves */
        printf("Request %3d -> goes to %2d%s\n", request, floor,
               floor != request ? " (corrected)" : "");
        current = floor;
    }
    printf("Corrected: %d | Floors travelled: %d\n", corrected, travelled);
    return 0;
}

Why it is written this way:

  • CLAMP(x, lo, hi) is MIN(MAX((x), (lo)), (hi)): MAX raises any request below −2 up to −2 and MIN lowers any above 8 down to 8. Macros can be nested: the preprocessor rescans the text that comes out of a replacement.
  • MIN_FLOOR is (-2) in parentheses by the usual rule: it is an expression, not a plain number.
  • int request = requests[i]; is the key decision. CLAMP ends up repeating x several times when expanded (there is a MAX inside a MIN, and each repeats its parameters), so with CLAMP(requests[i++], …) the index would advance several times in a single loop.
  • travelled += ABS(floor - current) adds the distance in floors, without sign: going down from 8 to −2 is 10 floors, the same as going up.

The trace loop by loop:

LooprequestfloorCorrected?ABS(floor - current)travelled
055No|5 − 0| = 55
1128Yes|8 − 5| = 38
2−4−2Yes|−2 − 8| = 1018
300No|0 − (−2)| = 220
488No|8 − 0| = 828
5−2−2No|−2 − 8| = 1038
698Yes|8 − (−2)| = 1048

Three corrected and 48 floors, as in the output.

Level 3 solution

First, lift.h:

/* lift.h: constants, macros and the simulator struct */
#ifndef LIFT_H
#define LIFT_H

#define MAX_LOAD 1500
#define AVG_WEIGHT 75
#define MAX_PEOPLE (MAX_LOAD / AVG_WEIGHT)          /* 20 */

#define ABS(x) ((x) < 0 ? -(x) : (x))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define DIV_UP(a, b) (((a) + (b) - 1) / (b))        /* division rounding up */

struct Group {
    int origin;
    int destination;
    int people;
};

#endif  /* LIFT_H */

Then, logger.h:

/* logger.h: traces that only exist when compiling with -DDEBUG */
#ifndef LOGGER_H
#define LOGGER_H

#include "lift.h"   /* included again from the .c: the guard prevents it */

#ifdef DEBUG
#define LOG(msg, value) printf("  [%s:%d] %s = %d\n", __FILE__, __LINE__, msg, value)
#else
#define LOG(msg, value) ((void)0)
#endif

#endif  /* LOGGER_H */

And the program:

#include <stdio.h>
#include "lift.h"
#include "logger.h"

#define NUM_GROUPS 5

int main(void) {
    struct Group day[NUM_GROUPS] = {
        {0, 6, 8}, {0, 3, 25}, {4, -1, 12}, {7, 0, 41}, {-2, 5, 3}
    };
    int total_trips = 0, total_floors = 0, fullest = 0;

    for (int i = 0; i < NUM_GROUPS; i++) {
        struct Group g = day[i];
        int trips = DIV_UP(g.people, MAX_PEOPLE);
        int leg = ABS(g.destination - g.origin);
        /* go, empty return for more people, go...: 2 * trips - 1 legs */
        int floors = leg * (2 * trips - 1);
        int in_cabin = MIN(g.people, MAX_PEOPLE);   /* the fullest trip of the group */
        LOG("trips", trips);
        LOG("floors", floors);

        printf("Group %d: %2d ppl. %2d -> %2d | %d trip(s), %2d floors\n",
               i + 1, g.people, g.origin, g.destination, trips, floors);
        total_trips += trips;
        total_floors += floors;
        if (in_cabin > fullest)
            fullest = in_cabin;
    }
    printf("Total: %d trips, %d floors, max %d people (%d kg) at once\n",
           total_trips, total_floors, fullest, fullest * AVG_WEIGHT);
    return 0;
}

Why it is written this way:

  • Both guards (LIFT_H and LOGGER_H) are essential: simulator.c includes lift.h directly and again through logger.h. Without the guard in lift.h, struct Group would be defined twice and it would not compile.
  • **DIV_UP(a, b)** is (((a) + (b) - 1) / (b)). With normal integer division, 41 / 20 = 2 and one person would be left on floor 7; adding 19 first, (41 + 19) / 20 = 60 / 20 = 3. If it was already exact, nothing changes: (40 + 19) / 20 = 59 / 20 = 2.
  • **floors = leg * (2 * trips - 1)**: with one trip, the leg once; with three, go, return, go, return, go = five times.
  • **MIN(g.people, MAX_PEOPLE)** is the number of people in the fullest trip of that group: if there are 8, all 8 go; if there are 41, at most 20.
  • **LOG** comes from logger.h, so the .c neither knows nor cares whether traces are on. __LINE__ says 20 and 21, the lines of simulator.c where it is used, even though the macro is written in another file.

The sums for each group:

GroupPeopletripslegfloorsIn the fullest trip
18(8 + 19) / 20 = 1|6 − 0| = 66 · 1 = 68
225(25 + 19) / 20 = 233 · 3 = 920
3121|−1 − 4| = 5512
441377 · 5 = 3520
531|5 − (−2)| = 773

Total: 1 + 2 + 1 + 3 + 1 = 8 trips and 6 + 9 + 5 + 35 + 7 = 62 floors; the fullest trip carries 20 people, 20 · 75 = 1500 kg. Group 4 is the most interesting one, and the drawing shows it in full:

Group 4 in the simulator Zigzag between floor 7 and floor 0: three trips down with 20, 20 and 1 people and two empty trips up; next to it, the sums: 3 trips, 5 legs of 7 floors, 35 floors. Group 4: 41 people from floor 7 to floor 0 floor 7 floor 0 20 empty 20 empty 1 trips = DIV_UP(41, 20) = (41 + 19) / 20 = 3 legs = 2 * 3 – 1 = 5 leg = ABS(0 – 7) = 7 floors = 7 * 5 = 35 Three trips with people (20 + 20 + 1) and two empty returns: five legs of seven floors.
DIV_UP rounds up: 41 / 20 would give 2 with integer division, and one person would be left on floor 7.

Watch it step by step in Python Tutor

Python Tutor runs the code line by line and draws the variables. Choose C and paste this version of snippet 1, which stores each step in a variable so you can watch the bug live:

#include <stdio.h>

#define MAX_LOAD 1500
#define TOO_BIG(v) v >= MAX_LOAD     /* no parentheses */

int main(void) {
    int load = 300;
    int negated = !load;                 /* what the ! really calculates */
    int result = !TOO_BIG(load); /* !load >= 1500 */
    int good = !(load >= MAX_LOAD);      /* what we wanted */
    printf("negated = %d, result = %d, good = %d\n", negated, result, good);
    return 0;
}

Its output:

negated = 0, result = 0, good = 1

What to watch step by step:

  1. **load is 300** and it is the only thing that exists at the start; neither MAX_LOAD nor the macro appear as variables.
  2. **When negated is created**, it is 0: !300 is 0, because any non-zero number counts as “true” and negating it gives “false”.
  3. **When result is created**, it is also 0. That is the macro without parentheses: !load >= 1500 is negated >= 1500, that is, 0 >= 1500.
  4. **When good is created**, it is 1: with the parentheses in the right place, 300 >= 1500 is 0 and negating it gives 1. That is the difference between “too much weight” and “can go up”.

Cheat sheet: the preprocessor in C

The essentials in 30 seconds: the preprocessor works before the compiler and only with text. #include pastes files, #define replaces symbols (and macros with parameters), #ifdef/#if keep or remove code, and gcc -D defines symbols from outside. In macros, parentheses around each parameter and around everything; never a ; at the end nor arguments with side effects.

Directives:

I want…CodeResult
A system library#include <stdio.h>stdio.h is pasted in
My own header#include "lift.h"Searched for in my folder
A constant#define MAX_LOAD 1500MAX_LOAD → 1500
A symbol with no value#define WITH_SCREENIt just exists
A macro#define WEIGHT(n) ((n) * 75)WEIGHT(a + b) → ((a + b) * 75)
To remove a symbol#undef WITH_SCREENIt stops existing
A multi-line macro\ at the end of each lineA single definition

Conditional compilation:

I want…CodeResult
Traces only with -DDEBUG#ifdef DEBUG … #endifWithout -DDEBUG, they disappear
A default value you can change#ifndef N / #define N 10 / #endif-DN=20 changes it
To pick a version by number#if MODEL == 1 … #elif … #else … #endifOnly one branch is left
To switch off a block#if 0 … #endifIt never reaches the compiler
To block a compilation#error "message"gcc stops with that message
To define from the terminalgcc -DDEBUG / gcc -DMODEL=2Like a #define on line 1

Templates from the exercises:

TemplateCodeResult
Weight of a group#define GROUP_WEIGHT(a, n) ((a) * 75 + (n) * 35)GROUP_WEIGHT(4, 2) → 370
Fits or not#define FITS(kg) ((kg) <= MAX_LOAD)FITS(1500) → 1
Minimum and maximum#define MIN(a, b) ((a) < (b) ? (a) : (b))MIN(12, 8) → 8
Clamp to a range#define CLAMP(x, lo, hi) MIN(MAX((x), (lo)), (hi))CLAMP(-4, -2, 8) → −2
Absolute value#define ABS(x) ((x) < 0 ? -(x) : (x))ABS(-10) → 10
Division rounding up#define DIV_UP(a, b) (((a) + (b) - 1) / (b))DIV_UP(41, 20) → 3
Trace with locationprintf("[%s:%d] ...", __FILE__, __LINE__, ...)[simulator.c:20] ...
.h guard#ifndef LIFT_H / #define LIFT_H / … / #endifIncluded only once

Symptom / likely cause:

SymptomLikely cause
A calculation with a macro gives a strange numberMissing parentheses around a parameter or around everything
A !MACRO(x) is never (or always) trueThe macro is missing its outer parentheses
statement with no effect on a line with a #define; at the end of the #define
A variable advances twiceYou passed i++ to a macro that repeats the parameter
Traces appear even though DEBUG is 0You use #ifdef DEBUG instead of #if DEBUG
redefinition of 'struct …'A .h without a guard included twice
Lots of undeclared in a rowLook at the first error: an #error or an #include that fails

Before you submit, ask yourself:

  1. Do all my macros have parentheses around each parameter and around the expression?
  2. Does any #define end in ;?
  3. Do my traces disappear when I compile without -DDEBUG (with no side effects inside them)?
  4. Do all my .h files have their #ifndef … #define … #endif guard?
Keep goingAll C (en) articles

Did this article help you? Here is how you can support SergioLearns →

Sigue aprendiendo

Leave a Reply

Your email address will not be published. Required fields are marked *