<p>I introduce <strong>C</strong> macros as a convenient way of using a single source file that can be used both when debugging code in development and for final delivery, without having to edit and and edit out test/debug code.</p>

<p>I am doing it, in particular, in the context of using the compiler development tools flex and bison, but it would be equally valid when using just <strong>C</strong>.</p>

<p>For example, say some particular function returns a value:</p>

<pre><code>return(THIS_VALUE);
</code></pre>

<p>The student may find it helpful to know what that value is. They could use an interactive debugger, in an IDE (such as Visual Studio), or a stand-alone debugger, such as gdb. Mentioning this makes them aware of the variety of development tools available to professional developers. I also mention that it can also be done without such tools, and code developers need to be aware of these wider varieties of debugging mechanisms. I indicate one of the primitive methods of doing is to add a <code>printf</code>, such as this:</p>

<pre><code>printf("%d\n",THIS_VALUE);
return(THIS_VALUE);
</code></pre>

<p>I show, using an example (in flex actually), how this can be helpful. I then explain some of the risks and weaknesses in doing this:</p>

<ul>
<li>We spawn two versions of the code, a production and debug version of the code</li>
<li>We have to keep editing the prints in and out and may miss some</li>
<li>We may make typos and not actually print the value being returned!</li>
</ul>

<p>I then illustrate with using the <strong>preprocessor</strong>, which they may or may not have encountered:</p>

<pre><code>#ifdef DEBUG
printf("The Value is: %d\n",THIS_VALUE);
#endif
return(THIS_VALUE);
</code></pre>

<p>I then explain how this can be enabled by using flags in <code>make</code> or <code>gcc</code> or other such tools. The next stage in the explanation shows what can happen when this debug coding happens in many many places:</p>

<pre><code>ONE:
#ifdef DEBUG
printf("The Value is: %d\n",THIS_ONE_VALUE);
#endif
return(THIS_ONE_VALUE);

TWO:
#ifdef DEBUG
printf("The Value is: %d\n",THIS_TWO_VALUE);
#endif
return(THIS_TWO_VALUE);

THREE:
#ifdef DEBUG
printf("The Value is: %d\n",THIS_THREE_VALUE);
#endif
return(THIS_THREE_VALUE);

/* The code does not really look like this. I'm just making paradigms */
</code></pre>

<p>I point out how really poor this code is, and how it should be <strong>re-factored</strong>. This provides an opportunity for discussing re-factoring code and the options available. One option that will immediately occur to the student might be to use some form of procedure or function, like this:</p>

<pre><code>int Trace(int The_Argument)
{
#ifdef DEBUG
printf("The Value is: %d\n",The_Argument);
#endif
return(The_Argument); 
}

ONE:
   return(Trace(THIS_ONE_VALUE));
TWO:
   return(Trace(THIS_TWO_VALUE));
THREE:
   return(Trace(THIS_THREE_VALUE));
</code></pre>

<p>Students can see that this re-factoring may have improved the code, but now has inefficiencies that the original did not. It also has become <em>type specific</em>, as types were introduced for the first time (not quite true as the format is typed).</p>

<p>At this point Macros can be introduced as a neat and useful way of conditionally including debug code with the problems of editing statements in and out from the source. Something like this:</p>

<pre><code>#ifdef DEBUG
       #define RETURN(x) printf("Returning " #x ": %d",x); return(x)
#else
       #define RETURN(x) return(x)
#endif

ONE:
   RETURN(THIS_ONE_VALUE);
TWO:
   RETURN(THIS_TWO_VALUE);
THREE:
   RETURN(THIS_THREE_VALUE);
</code></pre>

<p>This then enables me to explain about the concepts of Macros versus functions. It also shows <strong>C</strong> <em>stringification</em> and initiates further discussion of these techniques.</p>

<p>I'm now ready to point them at some more professional discussions of the value of Macros, and in particular I like Jonathan Leffler's Stack Overflow <a href="https://stackoverflow.com/a/1644898/4370109">answer</a>.</p>

<p>I reinforce this by putting in the specification of their assignment that their code should implement certain specific debug flags which I will enable when assessing their work. They have to then master the technique to get grade points, in addition to having just working code.</p>

<p>Finally, now they know about Macros, I can talk about inline functions, how a Macro can be used to define one, based on the examples above. It also enables me to talk about compiler optimisations and how the compiler might introduce inlining itself without explicit macros from the programmer.</p>

<p>(This is part of a compilers course so such topics will be core knowledge for them).</p>

CC BY-SA 3.0
2017-07-19T14:31:11.893Z
We're always glad to get more teachers here. This is a very thorough description of the lesson. Nicely done, and welcome to [cseducators.se]!
Ben I.
CC BY-SA 3.0
2017-07-19T16:08:20.040Z
This is much better than my example. :-) Welcome to CSE!
Ellen Spertus
CC BY-SA 3.0
2017-07-19T12:35:09.180Z
2017-07-19T14:34:29.080Z
2017-07-19T14:34:29.080Z
Brian Tompsett - 汤莱恩
<p>It is useful to create a macro to compute the maximum operation. The advantages of a macro over a function are:</p>

<ul>
<li>performance (which we all know is important to C programmers, although they can use an <code>inline</code> function)</li>
<li>polymorphism (C won't allow you to have a single or multiple functions named <code>max</code> for different numeric types)</li>
</ul>

<p>The implementation turns out to be nontrivial. The first version is likely to be:</p>

<pre><code>#define MAX(a,b) (a &gt; b ? a : b)
</code></pre>

<p>This has two problems. The first is the lack of parentheses, which can lead to incorrect order of operations. For example,</p>

<pre><code>MAX(c &amp;&amp; d, 1)
</code></pre>

<p>would become</p>

<pre><code>(c &amp;&amp; d &gt; 1 ? c &amp;&amp; d : 1)
</code></pre>

<p>whose meaning is the same as:</p>

<pre><code>(c &amp;&amp; (d &gt; 1)) ? (c &amp;&amp; d) : 1
</code></pre>

<p>This problem can be fixed by changing the definition to:</p>

<pre><code>#define MAX(a,b) ((a) &gt; (b) ? (a) : (b))
</code></pre>

<p>An additional problem is that evaluating <code>a</code> and <code>b</code> may have side effects. Consider:</p>

<pre><code>MAX(++c, ++d)
</code></pre>

<p>This expands into:</p>

<pre><code>((++c) &gt; (++d) ? (++c) : (++d))
</code></pre>

<p>As described <a href="https://stackoverflow.com/a/5323810/631051">on our sister site</a>, a better version is:</p>

<pre><code>#define MAX(a,b) ({
    typeof (a) _a = (a);\
    typeof (b) _b = (b); \
    _a &gt; _b ? _a : _b; })
</code></pre>

<p>This, of course, is ugly and will not work if you have variables named <code>_a</code> and <code>_b</code>.</p>

<p>I'm afraid I've done the opposite of what you've requested and provided an argument against C macros. (I use the above argument before teaching Scheme's hygienic macros so students appreciate them.)</p>

CC BY-SA 3.0
2017-07-19T06:14:16.753Z
Thank you for these examples! That latter point about Scheme is something the professor in the programming languages MOOC I'm taking brings up as well. Part of why I want to show macros is because of how awesome they have been to learn in Racket with hygiene being a key concept thereof. I may just be full of wishful thinking when it comes to C's macros...
Peter
CC BY-SA 3.0
2017-07-19T05:56:29.577Z
2017-07-19T05:56:29.577Z
Ellen Spertus
<p>Thanks to working with Racket recently, I've been spending a lot of time learning about and implementing non-trivial macros. In the process, I have been thinking about ways to apply this skill to my teaching. In particular, I teach students C (in the context of CS50 AP) and would like to show them <strong>simple but useful examples of macros in C</strong>.</p>

<p>I see the potential benefit as two-fold: 1) it would be helpful for discussing the C pre-processor when I teach the stages of compilation, and 2) it might help students write/understand code with information abstracted away in macros.</p>

<p>What lesson ideas (with code examples hopefully) do you have for introducing students to macros in C?</p>

<lesson-ideas><introductory-lesson><ap-cs-principles><c>
Lesson ideas for introducing macros in C
# Lesson ideas for introducing macros in C

(Asked by: username_0 on 2017-07-18)

Thanks to working with Racket recently, I've been spending a lot of time learning about and implementing non-trivial macros. In the process, I have been thinking about ways to apply this skill to my teaching. In particular, I teach students C (in the context of CS50 AP) and would like to show them **simple but useful examples of macros in C**.

I see the potential benefit as two-fold: 1) it would be helpful for discussing the C pre-processor when I teach the stages of compilation, and 2) it might help students write/understand code with information abstracted away in macros.

What lesson ideas (with code examples hopefully) do you have for introducing students to macros in C?

**Tags:** lesson-ideas, introductory-lesson, ap-cs-principles, c


---

## 2 answers

### Answer by username_1 on 2017-07-19. Score: 8

I introduce C macros as a convenient way of using a single source file that can be used both when debugging code in development and for final delivery, without having to edit and and edit out test/debug code.
I am doing it, in particular, in the context of using the compiler development tools flex and bison, but it would be equally valid when using just C.
For example, say some particular function returns a value:
return(THIS_VALUE);

The student may find it helpful to know what that value is. They could use an interactive debugger, in an IDE (such as Visual Studio), or a stand-alone debugger, such as gdb. Mentioning this makes them aware of the variety of development tools available to professional developers. I also mention that it can also be done without such tools, and code developers need to be aware of these wider varieties of debugging mechanisms. I indicate one of the primitive methods of doing is to add a printf, such as this:
printf("%d\n",THIS_VALUE);
return(THIS_VALUE);

I show, using an example (in flex actually), how this can be helpful. I then explain some of the risks and weaknesses in doing this:

We spawn two versions of the code, a production and debug version of the code
We have to keep editing the prints in and out and may miss some
We may make typos and not actually print the value being returned!

I then illustrate with using the preprocessor, which they may or may not have encountered:
#ifdef DEBUG
printf("The Value is: %d\n",THIS_VALUE);
#endif
return(THIS_VALUE);

I then explain how this can be enabled by using flags in make or gcc or other such tools. The next stage in the explanation shows what can happen when this debug coding happens in many many places:
ONE:
#ifdef DEBUG
printf("The Value is: %d\n",THIS_ONE_VALUE);
#endif
return(THIS_ONE_VALUE);

TWO:
#ifdef DEBUG
printf("The Value is: %d\n",THIS_TWO_VALUE);
#endif
return(THIS_TWO_VALUE);

THREE:
#ifdef DEBUG
printf("The Value is: %d\n",THIS_THREE_VALUE);
#endif
return(THIS_THREE_VALUE);

/* The code does not really look like this. I'm just making paradigms */

I point out how really poor this code is, and how it should be re-factored. This provides an opportunity for discussing re-factoring code and the options available. One option that will immediately occur to the student might be to use some form of procedure or function, like this:
int Trace(int The_Argument)
{
#ifdef DEBUG
printf("The Value is: %d\n",The_Argument);
#endif
return(The_Argument); 
}

ONE:
   return(Trace(THIS_ONE_VALUE));
TWO:
   return(Trace(THIS_TWO_VALUE));
THREE:
   return(Trace(THIS_THREE_VALUE));

Students can see that this re-factoring may have improved the code, but now has inefficiencies that the original did not. It also has become type specific, as types were introduced for the first time (not quite true as the format is typed).
At this point Macros can be introduced as a neat and useful way of conditionally including debug code with the problems of editing statements in and out from the source. Something like this:
#ifdef DEBUG
       #define RETURN(x) printf("Returning " #x ": %d",x); return(x)
#else
       #define RETURN(x) return(x)
#endif

ONE:
   RETURN(THIS_ONE_VALUE);
TWO:
   RETURN(THIS_TWO_VALUE);
THREE:
   RETURN(THIS_THREE_VALUE);

This then enables me to explain about the concepts of Macros versus functions. It also shows C stringification and initiates further discussion of these techniques.
I'm now ready to point them at some more professional discussions of the value of Macros, and in particular I like Jonathan Leffler's Stack Overflow answer.
I reinforce this by putting in the specification of their assignment that their code should implement certain specific debug flags which I will enable when assessing their work. They have to then master the technique to get grade points, in addition to having just working code.
Finally, now they know about Macros, I can talk about inline functions, how a Macro can be used to define one, based on the examples above. It also enables me to talk about compiler optimisations and how the compiler might introduce inlining itself without explicit macros from the programmer.
(This is part of a compilers course so such topics will be core knowledge for them).

> **Comments:**
> **username_2**: We're always glad to get more teachers here. This is a very thorough description of the lesson. Nicely done, and welcome to [cseducators.se]!  
> **username_3**: This is much better than my example. :-) Welcome to CSE!  

---

### Answer by username_3 on 2017-07-19. Score: 3

It is useful to create a macro to compute the maximum operation. The advantages of a macro over a function are:

performance (which we all know is important to C programmers, although they can use an inline function)
polymorphism (C won't allow you to have a single or multiple functions named max for different numeric types)

The implementation turns out to be nontrivial. The first version is likely to be:
#define MAX(a,b) (a > b ? a : b)

This has two problems. The first is the lack of parentheses, which can lead to incorrect order of operations. For example,
MAX(c && d, 1)

would become
(c && d > 1 ? c && d : 1)

whose meaning is the same as:
(c && (d > 1)) ? (c && d) : 1

This problem can be fixed by changing the definition to:
#define MAX(a,b) ((a) > (b) ? (a) : (b))

An additional problem is that evaluating a and b may have side effects. Consider:
MAX(++c, ++d)

This expands into:
((++c) > (++d) ? (++c) : (++d))

As described on our sister site, a better version is:
#define MAX(a,b) ({
    typeof (a) _a = (a);\
    typeof (b) _b = (b); \
    _a > _b ? _a : _b; })

This, of course, is ugly and will not work if you have variables named _a and _b.
I'm afraid I've done the opposite of what you've requested and provided an argument against C macros. (I use the above argument before teaching Scheme's hygienic macros so students appreciate them.)

> **Comments:**
> **username_0**: Thank you for these examples! That latter point about Scheme is something the professor in the programming languages MOOC I'm taking brings up as well. Part of why I want to show macros is because of how awesome they have been to learn in Racket with hygiene being a key concept thereof. I may just be full of wishful thinking when it comes to C's macros...  

---

