0% found this document useful (0 votes)
263 views7 pages

Variadic Macro Techniques in C

This document discusses techniques for writing variadic macros in C that can perform operations on each argument. It presents a "paired, sliding argument list" trick that uses two macros to select a specific argument from a variadic list. This trick is used to define macros that have different expansions depending on the number of arguments passed. As an example, a "for each" macro is defined that calls another macro once for each argument. The techniques allow writing macros that can iterate over variadic arguments or override behavior based on argument count.

Uploaded by

aamya
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)
263 views7 pages

Variadic Macro Techniques in C

This document discusses techniques for writing variadic macros in C that can perform operations on each argument. It presents a "paired, sliding argument list" trick that uses two macros to select a specific argument from a variadic list. This trick is used to define macros that have different expansions depending on the number of arguments passed. As an example, a "for each" macro is defined that calls another macro once for each argument. The techniques allow writing macros that can iterate over variadic arguments or override behavior based on argument count.

Uploaded by

aamya
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

12/3/2016

Variadicmacrostricks|Codecraft

Codecraft
software=science+art+people

Variadicmacrostricks
Haveyoueverwantedtowriteaforeachloopoveralltheargsofa
variadicmacro?Orhaveyoueverwantedtooverloadamacroonthe
numberofarguments?(Ifyouresayingtoyourself,goodgrief,why?
Illdescribeausecaseattheboomofthispost.)
Ilearnedhowtodothistoday,andIwantedtoblogaboutittocement
thetechniqueinmyownmind.

(hp://[Link]/1319/)
[Link]
spareyou:)Imagecredit:[Link]
[Link]

1/7

12/3/2016

Variadicmacrostricks|Codecraft

Simplevariadicmacros
Therstpieceofmagicyouneedtodosomethinglikethisis
__VA_ARGS__.Thisallowsyoutowritemacrosthattakeanarbitrary
numberofarguments,using...torepresentthemacrosparameters:
1 #deneeprintf(fmt,...)\
2 fprintf(stderr,fmt,__VA_ARGS__)
viewrawvariadic_macro_1hostedwith byGitHub
Nice.__VA_ARGS__isastandardfeatureofC99,andIveknownaboutit
[Link](andClangs)extension,
whichaachesspecialmeaningto##__VA_ARGS__ifitsprecededbya
commaitremovesthecommaif##__VA_ARGS__expandstonothing.IfI
changemymacrodenitionto:
1 #deneeprintf(fmt,...)\
2 fprintf(stderr,fmt,##__VA_ARGS)
viewrawfancier_variadic_macrohostedwith

byGitHub

Icannowcalleprintf("hello,world");withoutacomplaintfrom
thecompiler.

Butitsnotenough
Thatdoesntletmedoaforeachloop,[Link]
areexpanded,butIcantdoanythingwiththem,[Link]
namesformymacrosparametersjusttheanonymous.
Iwentpokingaround,notexpectingtondasolution,butIwas
pleasantlysurprised.

Thepaired,slidingarglisttrick
Thenextbuildingblockweneedisatechniquethatusestwo
complementarymacrosplus__VA_ARGS__toselectsomethingspecic
[Link]
[Link](hp://[Link]/a/11763277),andyoucan
parseitalloutdirectlyfromthere,[Link]
anexplanationthattakesitonestepatatime:
[Link]

2/7

12/3/2016

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Variadicmacrostricks|Codecraft

//Acceptanynumberofargs>=N,[Link],
//[Link]
//[Link]
//anunderscoreitsanimplementationdetail,notsomethingweexpectpeople
//tocalldirectly.
#dene_GET_NTH_ARG(_1,_2,_3,_4,N,...)N
//Counthowmanyargsareinavariadicmacro.OnlyworksforuptoN1args.
#deneCOUNT_VARARGS(...)_GET_NTH_ARG(__VA_ARGS__,4,3,2,1)
intmain(){
printf(onearg:%d\n,COUNT_VARARGS(1));
printf(threeargs:%d\n,COUNT_VARARGS(1,2,3));
}

//output
onearg:1
threeargs:3

viewrawpaired_sliding_arg_list_macro_trick_1hostedwith
GitHub

by

Seehowitworks?Therstmacro,_GET_NTH_ARG(),takesanynumber
ofargs>=N,butalwaysreturnsitemN(inthiscase,N=5).Thesecond
macro,COUNT_VARARGS(...),takesanarbitrarynumberofargs<N,
padswithcandidatevaluesitwantstoextract,andusesitsargstocall
_GET_NTH_ARG()inawaythatputstherightcandidatevalueinthe
[Link],themeaningfulpieceofinfothatwewant
inpositionNisanargcount;weveprovidedthevalues4,3,2,1as
candidatevalues,andoneofthosevalueswillbeinpositionNon
expansion.
TweakingthismacropairtohandleadierentNisamaerofadjusting
whatcomesbeforeNintherstmacro,andwhatcomesafter
__VA_ARGS__inthesecondmacro.Illleavethatasanexerciseforthe
reader.:)
Wedonthavetoselectanumericcountwiththistechnique;wecould
useittoselectargnameswiththe#operator,[Link]
[Link],letsaddressoneshortcoming:
COUNT_VARARGS(...)[Link]
x:
1
2
3

//Acceptanynumberofargs>=N,[Link]
//thatcallsusstillonlysupports4args,butthesetofvalueswemight
//needtoreturnis1larger,soweincreaseNto6.

[Link]

3/7

12/3/2016

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Variadicmacrostricks|Codecraft

#dene_GET_NTH_ARG(_1,_2,_3,_4,_5,N,...)N

//[Link]/Clangsextensionto
//handlethecasewhere...[Link]
//##__VA_ARGS__(itsvalueistotallyirrelevant,butitsnecessarytopreserve
//theshiftingosetwewant).Inaddition,wemustadd0asavalidvaluetobein
//theNposition.
#deneCOUNT_VARARGS(...)_GET_NTH_ARG(ignored,##__VA_ARGS__,4,3,2,1,0)
intmain(){
printf(zeroargs:%d\n,COUNT_VARARGS());
printf(threeargs:%d\n,COUNT_VARARGS(1,2,3));
}
//output
zeroargs:0
threeargs:3

viewrawpaired_sliding_arg_list_macro_trick_2hostedwith
GitHub

by

Macrooverrides
Now,wecanbuildonthistodeneavariadicmacrothathasan
[Link]
[Link]:
1
2
3
4
5
6
7
8
9
10
11
12
13
14

//Denetwooverridesthatcanbeusedbytheexpansionof
//ourmainmacro.
#dene_MY_CONCAT3(a,b,c)abc
#dene_MY_CONCAT2(a,b)ab
//Deneamacrothatusesthepaired,slidingarglist
//[Link]
//recognizethisassimilartotheGET_NTH_ARG()macroin
//previousexamples.
#dene_GET_OVERRIDE(_1,_2,_3,NAME,...)NAME
//Deneamacrothatconcatseither3or2stringstogether.
#deneMY_CONCAT(...)_GET_OVERRIDE(__VA_ARGS__,\
_MY_CONCAT3,_MY_CONCAT2)(__VA_ARGS__)

[Link]

4/7

12/3/2016

Variadicmacrostricks|Codecraft

15
16 intmain(){
17 printf(3args:%s\n,MY_CONCAT(a,b,c));
18 printf(2args:%s,MY_CONCAT(a,b));
19 }
20
21 //output
22 3args:abc
23 2args:ab
viewrawmacros_overridden_by_arg_counthostedwith byGitHub
Nowweregeingclosetobeingabletocodeaforeachloopoverall
[Link]
eachavor,itallcomestogether:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

//Acceptanynumberofargs>=N,butexpandtojusttheNthone.
//Here,N==6.
#dene_GET_NTH_ARG(_1,_2,_3,_4,_5,N,...)N
//Denesomemacrostohelpuscreateoverridesbasedonthe
//arityofaforeachstylemacro.
#dene_fe_0(_call,...)
#dene_fe_1(_call,x)_call(x)
#dene_fe_2(_call,x,...)_call(x)_fe_1(_call,__VA_ARGS__)
#dene_fe_3(_call,x,...)_call(x)_fe_2(_call,__VA_ARGS__)
#dene_fe_4(_call,x,...)_call(x)_fe_3(_call,__VA_ARGS__)
/**
*[Link]
*to4args.
*
*Exampleusage1:
*#deneFWD_DECLARE_CLASS(cls)classcls;
*CALL_MACRO_X_FOR_EACH(FWD_DECLARE_CLASS,Foo,Bar)
*
*Exampleusage2:
*#deneSTART_NS(ns)namespacens{
*#deneEND_NS(ns)}
*#deneMY_NAMESPACESSystem,Net,Hp
*CALL_MACRO_X_FOR_EACH(START_NS,MY_NAMESPACES)
*typedeffooint;
*CALL_MACRO_X_FOR_EACH(END_NS,MY_NAMESPACES)
*/

[Link]

5/7

12/3/2016

29
30
31

Variadicmacrostricks|Codecraft

#deneCALL_MACRO_X_FOR_EACH(x,...)\
_GET_NTH_ARG(ignored,##__VA_ARGS__,\
_fe_4,_fe_3,_fe_2,_fe_1,_fe_0)(x,##__VA_ARGS__)

viewrawfor_each_macrohostedwith

byGitHub

Okay,butwhy?
IsaidIdprovidesomeexplanationofwhythistechniquecouldbe
[Link],Iamnotafanofmacrosrewritingthesyntaxofa
programminglanguage;thatcanobscurewhatsreallyhappening,and
makeforasteeperlearningcurve.
Ontheotherhand,[Link]
codemuchlessverbose/repetitivebyeliminatingnoiseandboilerplate.
Occasionally,Irunintocaseswherethattradeoseemsworthittome.
Moreimportantly,macroshaveapropertythatyoucantgetanyother
waythesamefragmentofcodecanhavemultiplemeanings,andcan
maintainthissemanticparallelismwithoutbeingsusceptibletohuman
memoryerrors,laziness,[Link]
bloggedabouthowvaluablethiscanbeineliminatingencapuslation
problemswithenums(hps://[Link]/2012/10/29/howenums
spreaddiseaseandhowtocureit/),butIrecentlyfoundanotherneed
[Link]
(hps://[Link]/2013/10/24/onbreadrecipesmapsandintentions/),
Ihavetocreatesomefoundationpackagesandclassestheanalogto
[Link],[Link]
wrieninC/C++[Link]
somewaytousenamespaces,classes,andotherC++constructsinthe
sourcecode,butalsogeneratepackageandclassconstructsvisibletomy
[Link].
Theonlyproblemwasthatsomeofmymacrosneededtobevariadic
[Link].:)
Howaboutyou?Haveyoueverhadaneedforsomethinglikethis?
TUE,NOV25,2014
DANIELHARDMAN

MACROS,NAMESPACES,TRICKS,VARIADIC,__VA_ARGS__

2thoughtsonVariadicmacrostricks
[Link]
1.
JasonIveysays:

6/7

12/3/2016

Variadicmacrostricks|Codecraft

1.

JasonIveysays:
[Link]
macrosgetabadnamethesedays,thepreprocessoritselfisstilla
powerfulandwonderfultoolwhenusedfortheproblemsyou
described.
WhatIvediscoveredrecentlyasIhavebeenwritingcustommacros
isthatmany,ifnotall,oftheunderlyingcodeIinventisalready
[Link]
identicalsolutiontowhatyouhavecreatedabovebutIknowithasa
macrotoconvertthevar_argstoacountandlist.
(BOOST_PP_VARIADIC_TO_LIST)
Iwasalsopleasedtodiscoverthattheyhavethemechanicstoquickly
implementmyfavoritepreprocessorpaernyoutaughtmeyears
ago,theenumdeclarationviaincludele.(BOOST_PP_ITERATION)
Inmyopinion,[Link]
[Link]
alottheretoworkwith.
REPLY MON,JAN5,2015AT6:23PM
DanielHardmansays:
Jason:[Link],butIhavent
[Link]!Thanksforremindingmetolearn
aboutit.
WhenIrunintoaprogrammingproblemthatIdontknowhow
tosolve,Ioftenliketowritemyownsolutionnotsomuch
becauseIwantto*use*myownsolution,asbecauseIwantto
[Link]
ownsatisfaction(and,sometimes,wrienaboutitsoIunderstand
howitworkswell),thenIcanappreciateamoreelegantor
generalsolution,[Link]
[Link]
theintentcodebase;ifso,Illgladlyswitchover,sinceImalready
usingboostafairamount.
REPLY MON,JAN5,2015AT6:57PM

[Link].

[Link]

7/7

You might also like