[go: up one dir, main page]

0% found this document useful (0 votes)
106 views14 pages

Advanced Preprocessor Techniques

This document discusses advanced techniques for using the C preprocessor. It describes special preprocessor values like __DATE__ and __TIME__ that contain compilation information. It also explains string manipulation functions in the preprocessor, including the stringizing operator (#) and token-pasting operator (##), and provides examples of using them. Finally, it discusses how to write diagnostic debugging functions using the preprocessor, asserting conditions and printing error messages with file and line number information.

Uploaded by

mcolina11354
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
106 views14 pages

Advanced Preprocessor Techniques

This document discusses advanced techniques for using the C preprocessor. It describes special preprocessor values like __DATE__ and __TIME__ that contain compilation information. It also explains string manipulation functions in the preprocessor, including the stringizing operator (#) and token-pasting operator (##), and provides examples of using them. Finally, it discusses how to write diagnostic debugging functions using the preprocessor, asserting conditions and printing error messages with file and line number information.

Uploaded by

mcolina11354
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

CS106L

Spring 2009
Handout #08
April 16, 2009
Advanced Preprocessor Techniques
_________________________________________________________________________________________________________
Introduction
The previous handout on the preprocessor ended on a rather gri note, giving an e!aple o" preprocessor
usage gone a#r$% &ut to entirel$ esche# the preprocessor in "avor o" other language "eatures #ould also
'e an error% (n several circustances, the preprocessor can per"or tas)s that other C** language
"eatures cannot accoplish% This handout e!plores several areas #here the preprocessor can 'e an
invalua'le tool "or solving pro'les and points out several strengths and #ea)nesses o" preprocessor+
'ased approaches%
Special Preprocessor Values
The preprocessor has access to several special values that contain in"oration a'out the state o" the "ile
currentl$ 'eing copiled% The values act li)e #defined constants in that the$ are replaced #henever
encountered in a progra% ,or e!aple, the values __DATE__ and __TIME__ contain string
representations o" the date and tie that the progra #as copiled% Thus, $ou can #rite an
autoaticall$+generated -a'out this progra. "unction using s$nta! siilar to this/
string GetAboutInformation()
{
stringstream result;
result << "Tis !rogram "as #om!iled on " << __DATE__;
result << " at time " << __TIME__;
return result$str();
%
Siilarl$, there are t#o other values, __&I'E__ and __(I&E__, #hich contain the current line nu'er
and the nae o" the "ile 'eing copiled% 0e1ll see an e!aple o" #here __&I'E__ and __(I&E__ can
'e use"ul later in this handout%
String Manipulation Functions
0hile o"ten dangerous, there are ties #here acros can 'e ore po#er"ul or ore use"ul than regular
C** "unctions% Since acros #or) #ith source+level te!t strings instead o" at the C** language level,
soe pieces o" in"oration are availa'le to acros that are not accessi'le using other C** techni2ues%
,or e!aple, let1s return to the MA) acro #e used in the previous handout/
#define MA)(a* b) ((a) + (b) , (a) - (b))
Here, the arguents a and b to MA) are passed '$ string 3 that is, the arguents are passed as the strings
that copose the% ,or e!aple, MA)(./* .0) passes in the value ./ not as a nueric value ten, 'ut as
the character . "ollo#ed '$ the character /% The preprocessor provides t#o di""erent operators "or
anipulating the strings passed in as paraeters% ,irst is the stringizing operator, represented '$ the #
s$'ol, #hich returns a 2uoted, C string representation o" the paraeter% ,or e!aple, consider the
"ollo#ing acro/
+ 1 +
#define 12I'T34T(n) #out << #n << " as 5alue " << (n) << endl
Here, #e ta)e in a single paraeter, n% 0e then use the stringi4ing operator to print out a string
representation o" n, "ollo#ed '$ the value o" the e!pression n% ,or e!aple, given the "ollo#ing code
snippet/
int 6 7 .89;
12I'T34T(6 : ;<);
A"ter preprocessing, this $ields the C** code
int 6 7 .89;
#out << "6 : ;<" << " as 5alue " << (6 : ;<) << endl;
5ote that a"ter the a'ove progra has 'een copiled "ro C** to achine code, an$ notions o" the
original varia'le 6 or the individual e!pressions a)ing up the progra #ill have 'een copletel$
eliinated, since varia'les e!ist onl$ at the C** level% Ho#ever, through the stringi4ing operator, it is
possi'le to preserve a string version o" portions o" the C** source code in the "inal progra, as
deonstrated a'ove% This is use"ul #hen #riting diagnostic "unctions, as $ou1ll see later in this handout%
The second preprocessor string anipulation operator is the string concatenation operator, also )no#n as
the token-pasting operator% This operator, represented '$ ##, ta)es the string value o" a paraeter and
concatenates it #ith another string% ,or e!aple, consider the "ollo#ing acro/
#define DE=&A2E_M>_?A2(t@!e) t@!e m@_##t@!e
The purpose o" this acro is to allo# the user to speci"$ a t$pe 6"or e!aple, int7, and to autoaticall$
generate a varia'le declaration o" that t$pe #hose nae is m@_type, #here type is the paraeter t$pe.
Here, #e use the ## operator to ta)e the nae o" the t$pe and concatenate it #ith the string m@_% Thus,
given the "ollo#ing acro call/
DE=&A2E_M>_?A2(int);
The preprocessor #ould replace it #ith the code
int m@_int;
5ote that #hen #or)ing #ith the to)en+pasting operator, i" the result o" the concatenation does not "or a
single C** to)en 6a valid operator or nae7, the 'ehavior is unde"ined% ,or e!aple, calling
DE=&A2E_M>_?A2(#onst int) #ill have unde"ined 'ehavior, since concatenating the strings m@_ and
#onst int does not $ield a single string 6the result is #onst int m@_#onst int7%
Practical Applications of the Preprocessor I: Diagnostic Debugging Functions
0hen #riting a progra, at ties $ou a$ #ant to ensure that certain invariants a'out $our progra hold
true 3 "or e!aple, that certain pointers cannot 'e '4&&, that a value is al#a$s less than soe constant,
etc% 0hile in an$ cases these conditions should 'e chec)ed using a language "eature called exception
handling, in several cases it is accepta'le to chec) the at runtie using a standard li'rar$ acro called
assert% assert, e!ported '$ the header <#assert+, is a acro that chec)s to see that soe condition
holds true% (" so, the acro has no e""ect% 8ther#ise, it prints out the stateent that did not evaluate to
true, along #ith the "ile and line nu'er in #hich it #as #ritten, then terinates the progra% ,or
e!aple, consider the "ollo#ing code/
+ 2 +
5oid M@(un#tion(int :m@1tr)
{
assert(m@1tr A7 '4&&);
:m@1tr 7 .89;
%
(" a caller passes a null pointer into M@(un#tion, the assert stateent #ill halt the progra and print
out a essage that ight loo) soething li)e this/
Assertion (ailed- Bm@1tr A7 '4&&B- (ile- main$#!!* &ine- ;<
&ecause assert a'ruptl$ terinates the progra #ithout giving the rest o" the application a chance to
respond, $ou should not use assert as a general+purpose error+handling routine% (n practical so"t#are
developent, assert is usuall$ used to e!press prograer assuptions a'out the state o" e!ecution%
,or e!aple, assuing #e have soe enuerated t$pe =olor, suppose #e #ant to #rite a "unction that
returns #hether a color is a priar$ color% Here1s one possi'le ipleentation/
bool Is1rimar@=olor(=olor #)
{
s"it#(#)
{
#ase 2ed-
#ase Green-
#ase Clue-
return true;
default-
D: 3ter"ise* must not be a !rimar@ #olor$ :D
return false;
%
%
Here, i" the color is 2ed, Green, or Clue, #e return that the color is indeed a priar$ color% 8ther#ise,
#e return that it is not a priar$ color% Ho#ever, #hat happens i" the paraeter is not a valid =olor,
perhaps i" the call is Is1rimar@=olor(=olor(E.))9 (n this "unction, since #e assue that that the
paraeter is indeed a color, #e ight #ant to indicate that to the progra '$ e!plicitl$ putting in an
assert test% Here1s a odi"ied version o" the "unction, using assert and assuing the e!istence o" a
"unction Is=olor/
bool Is1rimar@=olor(=olor #)
{
assert(Is=olor(#)); DD Fe assume tat tis is reall@ a #olor$
s"it#(#)
{
#ase 2ed-
#ase Green-
#ase Clue-
return true;
default-
D: 3ter"ise* must not be a !rimar@ #olor$ :D
return false;
%
%
+ : +
5o#, i" the caller passes in an invalid =olor, the progra #ill halt #ith an assertion error pointing us to
the line that caused the pro'le% (" #e have a good de'ugger, #e should 'e a'le to "igure out #hich
caller erroneousl$ passed in an invalid =olor and can 'etter reed$ the pro'le% 0ere #e to ignore this
case entirel$, #e ight have considera'l$ ore trou'le de'ugging the error, since #e #ould have no
indication o" #here the pro'le originated%
;ou should not, ho#ever, use assert to chec) that input "ro Get&ine is correctl$+"ored, "or
e!aple, since it a)es "ar ore sense to repropt the user than to terinate the progra%
0hile assert can 'e used to catch a good nu'er o" prograer errors during developent, it has the
un"ortunate side+e""ect o" slo#ing a progra do#n at runtie 'ecause o" the overhead o" the e!tra
chec)ing involved% Conse2uentl$, ost a<or copilers disa'le the assert acro in release or
optii4ed 'uilds% This a$ see dangerous, since it eliinates chec)s "or pro'leatic input, 'ut is
actuall$ not a pro'le 'ecause, in theor$, $ou shouldn1t 'e copiling a release 'uild o" $our progra i"
assert stateents "ail during e!ecution%
=
&ecause assert is entirel$ disa'led in optii4ed 'uilds, $ou
should use assert onl$ to chec) that speci"ic relations hold true, never to chec) the return value o" a
"unction% (" an assert contains a call to a "unction, #hen assert is disa'led in release 'uilds, the
"unction #on1t 'e called, leading to di""erent 'ehavior in de'ug and release 'uilds% This is a persistent
source o" de'ugging headaches%
>sing the tools outlined in this handout, it1s possi'le "or us to #rite our o#n version o" the assert
acro, #hich #e1ll call =G./H&Assert, to see ho# to use the preprocessor to design such utilities% 0e1ll
split the #or) into t#o parts 3 a "unction called Do=G./H&Assert, #hich actuall$ per"ors the testing
and error+printing, and the acro =G./H&Assert, #hich #ill set up the paraeters to this "unction
appropriatel$% The Do=G./H&Assert "unction #ill loo) li)e this/
#in#lude <#stdlib+ DD for abort();
D: Tese !arameters "ill be assumed to be #orre#t$ :D
5oid Do=G./H&Assert(bool in5ariant* string statement* string file* int line)
{
if(Ain5ariant)
{
#err << "=G./H&Assert (ailedA" << endl;
#err << "E6!ression- " << statement << endl;
#err << "(ile- " << file << endl;
#err << "&ine- " << line << endl;
abort(); DD Iuits !rogram and signals error to te 3G$
%
%
This "unction ta)es in the e!pression to evaluate, along #ith a string representation o" that stateent, the
nae o" the "ile it is "ound in, and the line nu'er o" the initial e!pression% (t then chec)s the invariant,
and, i" it "ails, signals an error and 2uits the progra '$ calling abort()% Since these paraeters are
rather 'ul)$, #e1ll hide the 'ehind the scenes '$ #riting the =G./H&Assert acro as "ollo#s/
#define =G./H&Assert(e6!r) Do=G./H&Assert(e6!r* #e6!r* __(I&E__* __&I'E__)
This acro ta)es in a single paraeter, an e!pression e6!r, and passes it in to the Do=G./H&Assert
"unction% To set up the second paraeter to Do=G./H&Assert, #e get a string representation o" the
e!pression using the stringi4ing operator on e6!r% ,inall$, to get the "ile and line nu'ers, #e use the
= (n practice, this isn1t al#a$s the case% &ut it1s still a nice theor$?
+ @ +
special preprocessor s$'ols __(I&E__ and __&I'E__% 5ote that since the acro is e!panded at the
call site, __(I&E__ and __&I'E__ re"er to the "ile and line #here the acro is used, not #here it #as
declared%
To see =G./H&Assert in action, suppose #e a)e the "ollo#ing call to =G./H&Assert in m@file$#!!
at line .89% Aiven this code/
=G./H&Assert(m@1tr A7 '4&&);
The acro e!pands out to
Do=G./H&Assert(m@1tr A7 '4&&* "m@1tr A7 '4&&"* __(I&E__* __&I'E__);
0hich in turn e!pands to
Do=G./H&Assert(m@1tr A7 '4&&* "m@1tr A7 '4&&"* "m@file$#!!"* .89);
0hich is e!actl$ #hat #e #ant%
5o#, suppose that #e1ve used =G./H&Assert throughout a C** progra and have success"ull$
de'ugged an$ o" its parts% (n this case, #e #ant to disa'le =G./H&Assert "or a release 'uild, so that
the "inal progra doesn1t have the overhead o" all the runtie chec)s% To allo# the user to toggle #hether
=G./H&Assert has an$ e""ect, #e1ll let the #define a constant, '3_=G./H&_AGGE2T, that disa'les
the assertion% (" the user does not de"ine '3_=G./H&_AGGE2T, #e1ll use #define to have the
=G./H&Assert acro per"or the runtie chec)s% 8ther#ise, #e1ll have the acro do nothing% This is
easil$ accoplished using #ifndef %%% #else %%% #endif to deterine the 'ehavior o" =G./H&Assert%
This sart version o" =G./H&Assert is sho#n 'elo#/
+ B +
#ifndef '3_=G./H&_AGGE2T DD Enable assertions
#in#lude <#stdlib+ DD for abort();
D: 'ote tat "e define Do=G./H&Assert inside tis blo#J* sin#e if
: te ma#ro is disabled tereBs no reason to lea5e tis fun#tion sitting
: around$
:D
5oid Do=G./H&Assert(bool in5ariant* string statement* string file* int line)
{
if(Ain5ariant)
{
#err << "=G./H&Assert (ailedA" << endl;
#err << "E6!ression- " << statement << endl;
#err << "(ile- " << file << endl;
#err << "&ine- " << line << endl;
abort(); DD Iuits !rogram and signals error to te 3G$
%
%
#define =G./H&Assert(e6!r) Do=G./H&Assert(e6!r* #e6!r* __(I&E__* __&I'E__)
#else DD Disable assertions
D: Define =G./H&Assert as a ma#ro tat e6!ands to noting$ 'o"* if "e #all
: =G./H&Assert in our #ode* it as absolutel@ no effe#t$
:D
#define =G./H&Assert(e6!r) D: noting :D
#endif
Practical Applications of the Preprocessor II: The Macro Tric!
That acros give C** progras access to their o#n source code can 'e used in other #a$s as #ell% 8ne
lesser+)no#n prograing techni2ue is )no#n as the X Macro trick, a #a$ to speci"$ data in one "orat
'ut have it availa'le in several "orats%
&e"ore e!ploring the C Dacro tric), #e need to cover ho# to rede"ine a acro a"ter it has 'een declared%
Eust as $ou can de"ine a acro '$ using #define, $ou can also unde"ine a acro using #undef% The
#undef preprocessor directive ta)es in a s$'ol that has 'een previousl$ #defined and causes the
preprocessor to ignore the earlier de"inition% (" the s$'ol #as not alread$ de"ined, the #undef directive
has no e""ect 'ut is not an error% ,or e!aple, consider the "ollo#ing code snippet/
#define M>_I'T .89
int 6 7 M>_I'T; DD M>_I'T is re!la#ed
#undef M>_I'T;
int M>_I'T 7 ;<; DD M>_I'T not re!la#ed
The preprocessor #ill re#rite this code as
int 6 7 .89;
int M>_I'T 7 ;<;
Although M>_I'T #as once a #defined constant, a"ter encountering the #undef stateent, the
preprocessor stopped treating it as such% Thus, #hen encountering int M>_I'T 7 ;<, the preprocessor
+ 6 +
ade no replaceents and the code copiled as #ritten%
To introduce the C Dacro tric), let1s consider a coon prograing pro'le and see ho# #e should
go a'out solving it% Suppose that #e #ant to #rite a "unction that, given as an arguent an enuerated
t$pe, returns the string representation o" the enuerated value% ,or e!aple, given the enum
enum =olor {2ed* Green* Clue* =@an* Magenta* >ello"%;
0e #ant to #rite a "unction called =olorToGtring that returns a string representation o" the color% ,or
e!aple, passing in the constant 2ed should hand 'ac) the string "2ed", Clue should $ield "Clue", etc%
Since the naes o" enuerated t$pes are lost during copilation, #e #ould norall$ ipleent this
"unction using code siilar to the "ollo#ing/
string =olorToGtring(=olor #)
{
s"it#(#)
{
#ase 2ed- return "2ed";
#ase Clue- return "Clue";
#ase Green- return "Green";
#ase =@an- return "=@an";
#ase Magenta- return "Magenta";
#ase >ello"- return ">ello"";
default- return "<unJno"n+";
%
%
5o#, suppose that #e #ant to #rite a "unction that, given a color, returns the opposite color%
=
0e1d need
another "unction, li)e this one/
=olor Get3!!osite=olor(=olor #)
{
s"it#(#)
{
#ase 2ed- return =@an;
#ase Clue- return >ello";
#ase Green- return Magenta;
#ase =@an- return 2ed;
#ase Magenta- return Green;
#ase >ello"- return Clue;
default- return #; DD 4nJno"n #olor* undefined result
%
%
These t#o "unctions #ill #or) correctl$, and there1s nothing "unctionall$ #rong #ith the as #ritten%
The pro'le, though, is that these "unctions are not scalable% (" #e #ant to introduce ne# colors, sa$,
Fite and Cla#J, #e1d need to change 'oth =olorToGtring and Get3!!osite=olor to incorporate
these ne# colors% (" #e accidentall$ "orget to change one o" the "unctions, the copiler #ill give no
#arning that soething is issing and #e #ill onl$ notice pro'les during de'ugging% The pro'le is
that a color encapsulates ore in"oration than can 'e e!pressed in an enuerated t$pe% Colors also
have naes and opposites, 'ut the C** enum =olor )no#s onl$ a uni2ue (F "or each color and relies on
correct ipleentations o" =olorToGtring and Get3!!osite=olor "or the other t#o% Soeho#,
= ,or the purposes o" this e!aple, #e1ll #or) #ith additive colors% Thus red is the opposite o" c$an, $ello# is the
opposite o" 'lue, etc%
+ G +
#e1d li)e to 'e a'le to group all o" this in"oration into one place% 0hile #e ight 'e a'le to accoplish
this using a set o" C** stru#t constants 6e%g% de"ining a color stru#t and a)ing #onst instances o"
these stru#ts "or each color7, this approach can 'e 'ul)$ and tedious% (nstead, #e1ll choose a di""erent
approach '$ using C Dacros%
The idea 'ehind C Dacros is that #e can store all o" the in"oration needed a'ove inside o" calls to
preprocessor acros% (n the case o" a color, #e need to store a color1s nae and opposite% Thus, let1s
suppose that #e have soe acro called DE(I'E_=3&32 that ta)es in t#o paraeters corresponding to
the nae and opposite color% 0e ne!t create a ne# "ile, #hich #e1ll call #olor$, and "ill it #ith calls to
this DE(I'E_=3&32 acro that e!press all o" the colors #e )no# 6let1s ignore the "act that #e haven1t
actuall$ de"ined DE(I'E_=3&32 $etH #e1ll get there in a oent7% This "ile loo)s li)e this/
File: color.h
DE(I'E_=3&32(2ed* =@an)
DE(I'E_=3&32(=@an* 2ed)
DE(I'E_=3&32(Green* Magenta)
DE(I'E_=3&32(Magenta* Green)
DE(I'E_=3&32(Clue* >ello")
DE(I'E_=3&32(>ello"* Clue)
T#o things a'out this "ile should <up out at $ou% ,irst, #e haven1t surrounded the "ile in the traditional
#ifndef %%% #endif 'oilerplate, so clients can #in#lude this "ile ultiple ties% Second, #e haven1t
provided an ipleentation "or DE(I'E_=3&32, so i" a caller does include this "ile, it #ill cause a
copile+tie error% ,or no#, don1t #orr$ a'out these pro'les 3 $ou1ll see #h$ #e1ve structured the "ile
this #a$ in a oent%
Let1s see ho# #e can use the C Dacro tric) to re#rite Get3!!osite=olor, #hich "or convenience is
reprinted 'elo#/
=olor Get3!!osite=olor(=olor #)
{
s"it#(#)
{
#ase 2ed- return =@an;
#ase Clue- return >ello";
#ase Green- return Magenta;
#ase =@an- return 2ed;
#ase Magenta- return Green;
#ase >ello"- return Clue;
default- return #; DD 4nJno"n #olor* undefined result
%
%
Here, each one o" the #ase la'els in this s#itch stateent is #ritten as soething o" the "or
#ase color- return opposite;
Loo)ing 'ac) at our #olor$ "ile, notice that each DE(I'E_=3&32 acro has the "or
DE(I'E_=3&32(color* opposite)% This suggests that #e could soeho# convert each o" these
DE(I'E_=3&32 stateents into a #ase la'el '$ cra"ting the proper #define% (n our case, #e1d #ant the
#define to a)e the "irst paraeter the arguent o" the #ase la'el and the second paraeter the return
value% 0e can thus #rite this #define as
+ 8 +
#define DE(I'E_=3&32(#olor* o!!osite) #ase #olor- return o!!osite;
Thus, #e can re#rite Get3!!osite=olor using C Dacros as
=olor Get3!!osite=olor(=olor #)
{
s"it#(#)
{
#define DE(I'E_=3&32(#olor* o!!osite) #ase #olor- return o!!osite;
#in#lude "#olor$"
#undef DE(I'E_=3&32
default- return #; DD 4nJno"n #olor* undefined result$
%
%
This is prett$ cr$ptic, so let1s #al) through it one step at a tie% ,irst, let1s siulate the preprocessor '$
replacing the line #in#lude "#olor$" #ith the "ull contents o" #olor$/
=olor Get3!!osite=olor(=olor #)
{
s"it#(#)
{
#define DE(I'E_=3&32(#olor* o!!osite) #ase #olor- return o!!osite;
DE(I'E_=3&32(2ed* =@an)
DE(I'E_=3&32(=@an* 2ed)
DE(I'E_=3&32(Green* Magenta)
DE(I'E_=3&32(Magenta* Green)
DE(I'E_=3&32(Clue* >ello")
DE(I'E_=3&32(>ello"* Clue)
#undef DE(I'E_=3&32
default- return #; DD 4nJno"n #olor* undefined result$
%
%
5o#, #e replace each DE(I'E_=3&32 '$ instantiating the acro, #hich $ields the "ollo#ing/
=olor Get3!!osite=olor(=olor #)
{
s"it#(#)
{
#ase 2ed- return =@an;
#ase Clue- return >ello";
#ase Green- return Magenta;
#ase =@an- return 2ed;
#ase Magenta- return Green;
#ase >ello"- return Clue;
#undef DE(I'E_=3&32
default- return #; DD 4nJno"n #olor* undefined result$
%
%
,inall$, #e #undef the DE(I'E_=3&32 acro, so that the ne!t tie #e need to provide a de"inition "or
DE(I'E_=3&32, #e don1t have to #orr$ a'out con"licts #ith the e!isting declaration% Thus, the "inal
code "or Get3!!osite=olor, a"ter e!panding out the acros, $ields
+ 9 +
=olor Get3!!osite=olor(=olor #)
{
s"it#(#)
{
#ase 2ed- return =@an;
#ase Clue- return >ello";
#ase Green- return Magenta;
#ase =@an- return 2ed;
#ase Magenta- return Green;
#ase >ello"- return Clue;
default- return #; DD 4nJno"n #olor* undefined result$
%
%
0hich is e!actl$ #hat #e #anted%
The "undaental idea underl$ing the C Dacros tric) is that all o" the in"oration #e can possi'l$ need
a'out a color is contained inside o" the "ile #olor$% To a)e that in"oration availa'le to the outside
#orld, #e e'ed all o" this in"oration into calls to soe acro #hose nae and paraeters are )no#n%
0e do not, ho#ever, provide an ipleentation o" this acro inside o" #olor$ 'ecause #e cannot
anticipate ever$ possi'le use o" the in"oration contained in this "ile% (nstead, #e e!pect that i" another
part o" the code #ants to use the in"oration, it #ill provide its o#n ipleentation o" the
DE(I'E_=3&32 acro that e!tracts and "orats the in"oration% The 'asic idio "or accessing the
in"oration "ro these acros loo)s li)e this/
#define macroname(arguments) D: some use for te arguments :D
#in#lude "filename"
#undef macroname
Here, the "irst line de"ines the echanis #e #ill use to e!tract the data "ro the acros% The second
includes the "ile containing the acros, #hich supplies the acro the data it needs to operate% The "inal
step clears the acro so that the in"oration is availa'le to other callers% (" $ou1ll notice, the a'ove
techni2ue "or ipleenting Get3!!osite=olor "ollo#s this pattern precisel$%
0e can also use the a'ove pattern to re#rite the =olorToGtring "unction% 5ote that inside o"
=olorToGtring, #hile #e can ignore the second paraeter to DE(I'E_=3&32, the acro #e de"ine to
e!tract the in"oration still needs to have t#o paraeters% To see ho# to ipleent =olorToGtring,
let1s "irst revisit our original ipleentation/
string =olorToGtring(=olor #)
{
s"it#(#)
{
#ase 2ed- return "2ed";
#ase Clue- return "Clue";
#ase Green- return "Green";
#ase =@an- return "=@an";
#ase Magenta- return "Magenta";
#ase >ello"- return ">ello"";
default- return "<unJno"n+";
%
%
(" $ou1ll notice, each o" the #ase la'els is #ritten as
+ 10 +
#ase color- return "color";
Thus, using C Dacros, #e can #rite =olorToGtring as
string =olorToGtring(=olor #)
{
s"it#(#)
{
D: =on5ert someting of te form DE(I'E_=3&32(#olor* o!!osite)
: into someting of te form B#ase #olor- return "#olor"B;
:D
#define DE(I'E_=3&32(#olor* o!!osite) #ase #olor- return ##olor;
#in#lude "#olor$"
#undef DE(I'E_=3&32
default- return "<unJno"n+";
%
%
(n this particular ipleentation o" DE(I'E_=3&32, #e use the stringi4ing operator to convert the
#olor paraeter into a string "or the return value% 0e1ve used the preprocessor to generate 'oth
Get3!!osite=olor and =olorToGtring?
There is one "inal step #e need to ta)e, and that1s to re#rite the initial enum =olor using the C Dacro
tric)% 8ther#ise, i" #e a)e an$ changes to #olor$, perhaps renaing a color or introducing ne#
colors, the enum #ill not re"lect these changes and ight result in copile+tie errors% Let1s revisit
enum =olor, #hich is reprinted 'elo#/
enum =olor {2ed* Green* Clue* =@an* Magenta* >ello"%;
0hile in the previous e!aples o" =olorToGtring and Get3!!osite=olor there #as a reasona'l$
o'vious apping 'et#een DE(I'E_=3&32 acros and #ase stateents, it is less o'vious ho# to
generate this enum using the C Dacro tric)% Ho#ever, i" #e re#rite this enum as "ollo#s/
enum =olor {
2ed*
Green*
Clue*
=@an*
Magenta*
>ello"
%;
(t should 'e slightl$ easier to see ho# to #rite this enum in ters o" C Dacros% ,or each DE(I'E_=3&32
acro #e provide, #e1ll sipl$ e!tract the "irst paraeter 6the color nae7 and append a coa% (n
code, this loo)s li)e
enum =olor {
#define DE(I'E_=3&32(#olor* o!!osite) #olor* DD 'ame follo"ed b@ #omma
#in#lude "#olor$"
#undef DE(I'E_=3&32
%;
This, in turn, e!pands out to
+ 11 +
enum =olor {
#define DE(I'E_=3&32(#olor* o!!osite) #olor*
DE(I'E_=3&32(2ed* =@an)
DE(I'E_=3&32(=@an* 2ed)
DE(I'E_=3&32(Green* Magenta)
DE(I'E_=3&32(Magenta* Green)
DE(I'E_=3&32(Clue* >ello")
DE(I'E_=3&32(>ello"* Clue)
#undef DE(I'E_=3&32
%;
0hich in turn 'ecoes
enum =olor {
2ed*
Green*
Clue*
=@an*
Magenta*
>ello"*
%;
0hich is e!actl$ #hat #e #ant% ;ou a$ have noticed that there is a trailing coa at a"ter the "inal
color 6>ello"7, 'ut this is not a pro'le 3 it turns out that it1s totall$ legal C** code%
Anal"sis of the Macro Tric!
The C Dacro+generated "unctions have several advantages over the hand+#ritten versions% ,irst, it a)es
the code considera'l$ shorter% &$ rel$ing on the preprocessor to per"or the necessar$ e!pansions, #e
can e!press all o" the necessar$ in"oration "or an o'<ect inside o" an C Dacro "ile and onl$ need to #rite
the s$nta! necessar$ to per"or soe tas) once% Second, and ore iportantl$, this approach eans that
adding or reoving =olor values is siple% 0e sipl$ need to add another DE(I'E_=3&32 de"inition
to #olor$ and the changes #ill autoaticall$ appear in all o" the relevant "unctions% ,inall$, i" #e need
to incorporate ore in"oration into the =olor o'<ect, #e can store that in"oration in one location and
let an$ callers that need it access it #ithout accidentall$ leaving one out%
That said, C Dacros are not a per"ect techni2ue% The s$nta! is considera'l$ tric)ier and denser than in
the original ipleentation, and it1s less clear to an outside reader ho# the code #or)s% Iee'er that
reada'le code is <ust as iportant as correct code, and a)e sure that $ou1ve considered all o" $our
options 'e"ore settling on C Dacros% (" $ou1re ever #or)ing in a group and plan on using the C Dacro
tric), 'e sure that $our other group e'ers are up to speed on the techni2ue and get their approval
'e"ore using it%
=
= The C Dacro tric) is a special case o" a ore general techni2ue )no#n as preprocessor metaprogramming. ("
$ou1re interested in learning ore a'out preprocessor etaprograing, consider loo)ing into the &oost
Detaprograing Li'rar$ 6DJL7, a pro"essional C** pac)age that sipli"ies coon etaprograing tas)s%
+ 12 +
More to #$plore % Practice Proble&s
(1ve co'ined the -Dore to K!plore. and -Jractice Jro'les. section o" this handout 'ecause an$ o"
the topics #e didn1t cover in great detail in this handout are 'est understood '$ pla$ing around #ith the
aterial% Here1s a sapling o" di""erent preprocessor tric)s and techni2ues, i!ed in #ith soe
prograing pu44les/
1% A coon 'ut nonstandard variant o" the assert acro is the 5erif@ acro #hich, li)e
assert, chec)s a condition at runtie and prints and error and terinates i" the condition is
"alse% Ho#ever, in optii4ed 'uilds, 5erif@ is not disa'led, 'ut sipl$ does not a'ort at
runtie i" the condition is "alse% This allo#s $ou to use 5erif@ to chec) the return value o"
"unctions directl$ 6Fo $ou see #h$97% Create a "unction called =G./H&?erif@ that, unless the
s$'ol '3_=G./H&_?E2I(> is de"ined, chec)s the paraeter and a'orts the progra i" it is
"alse% 8ther#ise, i" '3_=G./H&_?E2I(> is de"ined, chec) the condition, 'ut do not terinate
the progra i" it is "alse%
2% Another coon de'ugging acro is a -not reached. acro #hich autoaticall$ terinates the
progra i" e!ecuted% -5ot reached. acros are use"ul inside constructs such as s"it#
stateents #here the default la'el should never 'e encountered% 0rite a acro,
=G./H&'ot2ea#ed, that ta)es in a string paraeter and, i" e!ecuted, prints out the string, "ile
nae, and line nu'er, then calls abort to end the progra% As #ith =G./H&Assert and
=G./H&?erif@, i" the user #defines the s$'ol '3_=G./H&_'3T2EA=KED, change the
'ehavior o" =G./H&'ot2ea#ed so that it has no e""ect%
:% (" $ou1ve done the t#o previous pro'les, $ou1ll notice that #e no# have three constants,
'3_=G./H&_AGGE2T, '3_=G./H&_?E2I(>, and '3_=G./H&_'3T2EA=KED, that all ust 'e
#defined to disa'le the at runtie% This can 'e a hassle and could potentiall$ 'e incorrect i"
#e accidentall$ oit one o" these s$'ols% 0rite a code snippet that chec)s to see i" a s$'ol
naed DIGAC&E_A&&_=G./H&_DEC4G is de"ined and, i" so, disa'les all o" the three
a"oreentioned de'ugging tools% Ho#ever, still give the user the option to selectivel$ disa'le the
individual "unctions%
@% Dodi"$ the earlier de"inition o" enum =olor such that a"ter all o" the colors de"ined in #olor$,
there is a special value, '3T_A_=3&32, that speci"ies a none!istent color% (Hint: Do you actually
need to change color.h to do this!
B% >sing C Dacros, #rite a "unction GtringTo=olor #hich ta)es as a paraeter a string and
returns the =olor o'<ect #hose nae exactly atches the input string% (" there are no colors #ith
that nae, return '3T_A_=3&32 as a sentinel% ,or e!aple, calling
GtringTo=olor("Green") #ould return the value Green, 'ut calling
GtringTo=olor("green") or GtringTo=olor("3li5e") should 'oth return
'3T_A_=3&32%
6% Suppose that $ou #ant to a)e sure that the enuerated values $ou1ve ade "or =olor do not
con"lict #ith other enuerated t$pes that ight 'e introduced into $our progra% Dodi"$ the
earlier de"inition o" DE(I'E_=3&32 used to de"ine enum =olor so that all o" the colors are
pre"aced #ith the identi"ier e=olor_% ,or e!aple, the old value 2ed should change to
e=olor_2ed, the old Clue #ould 'e e=olor_Clue, etc% Fo not change the contents o"
#olor$% (Hint: "se one o# the preprocessor string-manipulation operators!
+ 1: +
G% The #error directive causes a copile+tie error i" the preprocessor encounters it% This a$
sound strange at "irst, 'ut is an e!cellent #a$ "or detecting pro'les during preprocessing that
ight sno#'all into larger pro'les later in the code% ,or e!aple, i" the code uses copiler+
speci"ic "eatures 6such as the 8penDJ li'rar$7, it ight add a chec) to see that a copiler+
speci"ic #define is in place, using #error to report an error i" it isn1t% The s$nta! "or #error
is #error message, #here message is a essage to the user e!plaining the pro'le% Dodi"$
#olor$ so that i" a caller #in#ludes the "ile #ithout "irst #define+ing the DE(I'E_=3&32
acro, the preprocessor reports an error containing a essage a'out ho# to use the "ile%
8% (" $ou1re up "or a challenge, consider the "ollo#ing pro'le% &elo# is a ta'le suari4ing
various units o" length/
'nit (a&e )&eters % unit Suffi$ S"ste&
Deter 1%0 Detric
Centieter 0%01 c Detric
Liloeter 1000%0 ) Detric
,oot 0%:0@8 "t Knglish
(nch 0%02B@ in Knglish
Dile 1609%:@@ i Knglish
Astronoical >nit 1%@96 ! 10
11
A> Astronoical
Light ;ear 9%@61 M 10
1B
l$ Astronoical
Cu'it
=
0%BB cu'it Archaic
a7 Create a "ile called units$ that uses the C acros tric) to encode the a'ove in"oration%
'7 Create an enuerated t$pe, &engt4nit, #hich uses the su""i! o" the unit, preceded '$
e&engt4nit_, as the nae "or the unit% ,or e!aple, a cu'it is e&engt4nit_#ubit,
#hile a ile #ould 'e e&engt4nit_mi% Also de"ine an enuerated value
e&engt4nit_E2232 that serves as a sentinel indicating that the value is invalid%
c7 0rite a "unction called Guffi6GtringTo&engt4nit that accepts a string representation
o" a su""i! and returns the &engt4nit corresponding to that string% (" the string does not
atch the su""i!, return e&engt4nit_E2232%
d7 Create a stru#t, &engt, that stores a double and a &engt4nit% 0rite a "unction
2ead&engt that propts the user "or a double and a string representing an aount and
a unit su""i! and stores data in a &engt% (" the string does not correspond to a su""i!,
repropt the user% ;ou can odi"$ the code "or GetInteger on the CS106L #e'site to
a)e an ipleentation o" Get2eal%
e7 Create a "unction, Get4nitT@!e, that ta)es in a &engt and returns the unit s$ste in
#hich it occurs 6as a string7
"7 Create a "unction, 1rint&engt, that prints out a &engt in the "orat
amount suffix (amount unitnames)% ,or e!aple, i" a &engt stores 10@%2 iles, it
#ould print out ./;$<mi (./;$< Miles)
g7 Create a "unction, =on5ertToMeters, #hich ta)es in a &engt and converts it to an
e2uivalent length in eters%
Surprisingl$, this pro'le is not particularl$ long 3 the ain challenge is the user input, not the
unit anageent?
= There is no agreed+upon standard "or this unit, so this is an appro!iate average o" the various lengths%
+ 1@ +

You might also like