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

Variadic Macros Tricks - Codecraft

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)
216 views7 pages

Variadic Macros Tricks - Codecraft

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
You are on page 1/ 7

12/3/2016

Variadicmacrostricks|Codecraft

Codecraft
software=science+art+people

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

(hp://xkcd.com/1319/)
WhathappenedwhenIdecidedtolearnthistechnique.Imtryingto
spareyou:)Imagecredit:xkcd.com
https://codecraft.co/2014/11/25/variadicmacrostricks/

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
foralongtime.IvealsoknownaboutGCC(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,though.AlltheargsthatIpass
areexpanded,butIcantdoanythingwiththem,individually.Ihaveno
namesformymacrosparametersjusttheanonymous.
Iwentpokingaround,notexpectingtondasolution,butIwas
pleasantlysurprised.

Thepaired,slidingarglisttrick
Thenextbuildingblockweneedisatechniquethatusestwo
complementarymacrosplus__VA_ARGS__toselectsomethingspecic
outofamacroarglistofunknownsize.Ifounditinanansweron
stackoverow.com(hp://stackoverow.com/a/11763277),andyoucan
parseitalloutdirectlyfromthere,butthemagicsalileopaque.Heres
anexplanationthattakesitonestepatatime:
https://codecraft.co/2014/11/25/variadicmacrostricks/

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,butexpandtojusttheNthone.Inthiscase,
//wehaveseledon5asN.Wecouldpickadierentnumberbyadjusting
//thecountofthrowawayargsbeforeN.Notethatthismacroisprecededby
//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
knownNposition.Inthiscase,themeaningfulpieceofinfothatwewant
inpositionNisanargcount;weveprovidedthevalues4,3,2,1as
candidatevalues,andoneofthosevalueswillbeinpositionNon
expansion.
TweakingthismacropairtohandleadierentNisamaerofadjusting
whatcomesbeforeNintherstmacro,andwhatcomesafter
__VA_ARGS__inthesecondmacro.Illleavethatasanexerciseforthe
reader.:)
Wedonthavetoselectanumericcountwiththistechnique;wecould
useittoselectargnameswiththe#operator,orevenothermacros.This
willcomeinhandyinamoment.Butrst,letsaddressoneshortcoming:
COUNT_VARARGS(...)doesnthandlethecaseofzeroargs.Heresthe
x:
1
2
3

//Acceptanynumberofargs>=N,butexpandtojusttheNthone.Themacro
//thatcallsusstillonlysupports4args,butthesetofvalueswemight
//needtoreturnis1larger,soweincreaseNto6.

https://codecraft.co/2014/11/25/variadicmacrostricks/

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

//Counthowmanyargsareinavariadicmacro.WenowuseGCC/Clangsextensionto
//handlethecasewhere...expandstonothing.Wemustaddaplaceholderargbefore
//##__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
expansionoverriddenbyhowmanyargsitreceives.Thisiswhatthe
originalstackoverowanswerdid.Somethinglikethis:
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
//techniquetoselecttheappropriateoverride.Youshould
//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__)

https://codecraft.co/2014/11/25/variadicmacrostricks/

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
theargstoavariadicmacro.Ifthemacrothatgetsoverriddenhasafor
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__)
/**
*Provideaforeachconstructforvariadicmacros.Supportsup
*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)
*/

https://codecraft.co/2014/11/25/variadicmacrostricks/

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
useful.Ingeneral,Iamnotafanofmacrosrewritingthesyntaxofa
programminglanguage;thatcanobscurewhatsreallyhappening,and
makeforasteeperlearningcurve.
Ontheotherhand,sometimestheyarereallyhelpful.Theycanmake
codemuchlessverbose/repetitivebyeliminatingnoiseandboilerplate.
Occasionally,Irunintocaseswherethattradeoseemsworthittome.
Moreimportantly,macroshaveapropertythatyoucantgetanyother
waythesamefragmentofcodecanhavemultiplemeanings,andcan
maintainthissemanticparallelismwithoutbeingsusceptibletohuman
memoryerrors,laziness,ormisunderstanding.Ihavepreviously
bloggedabouthowvaluablethiscanbeineliminatingencapuslation
problemswithenums(hps://codecraft.co/2012/10/29/howenums
spreaddiseaseandhowtocureit/),butIrecentlyfoundanotherneed
forit.Inmyprojecttocreateanewprogramminglanguage
(hps://codecraft.co/2013/10/24/onbreadrecipesmapsandintentions/),
Ihavetocreatesomefoundationpackagesandclassestheanalogto
java.langinjava,orSystemandMyin.NET.Thisfoundationneedsto
wrieninC/C++toavoidachickenandeggproblem.ThatmeansIneed
somewaytousenamespaces,classes,andotherC++constructsinthe
sourcecode,butalsogeneratepackageandclassconstructsvisibletomy
intentcompiler.Macroswereanobviousanswer.
Theonlyproblemwasthatsomeofmymacrosneededtobevariadic
andIneededforeachstylesemantics.Hencemyresearch.:)
Howaboutyou?Haveyoueverhadaneedforsomethinglikethis?
TUE,NOV25,2014
DANIELHARDMAN

MACROS,NAMESPACES,TRICKS,VARIADIC,__VA_ARGS__

2thoughtsonVariadicmacrostricks
https://codecraft.co/2014/11/25/variadicmacrostricks/
1.
JasonIveysays:

6/7

12/3/2016

Variadicmacrostricks|Codecraft

1.

JasonIveysays:
Ilovethepreprocessorforexactlythiskindofwork.Although
macrosgetabadnamethesedays,thepreprocessoritselfisstilla
powerfulandwonderfultoolwhenusedfortheproblemsyou
described.
WhatIvediscoveredrecentlyasIhavebeenwritingcustommacros
isthatmany,ifnotall,oftheunderlyingcodeIinventisalready
wrienintheboost.preprocessorlibrary.Imnotsureifithasan
identicalsolutiontowhatyouhavecreatedabovebutIknowithasa
macrotoconvertthevar_argstoacountandlist.
(BOOST_PP_VARIADIC_TO_LIST)
Iwasalsopleasedtodiscoverthattheyhavethemechanicstoquickly
implementmyfavoritepreprocessorpaernyoutaughtmeyears
ago,theenumdeclarationviaincludele.(BOOST_PP_ITERATION)
Inmyopinion,theboost.preprocessorlibrarydocumentationleavesa
liletobedesiredintermsofexamplesanddescriptions.Butthereis
alottheretoworkwith.
REPLY MON,JAN5,2015AT6:23PM
DanielHardmansays:
Jason:Iverunintoboost.preprocessorafewtimes,butIhavent
useditmuch.Shameonme!Thanksforremindingmetolearn
aboutit.
WhenIrunintoaprogrammingproblemthatIdontknowhow
tosolve,Ioftenliketowritemyownsolutionnotsomuch
becauseIwantto*use*myownsolution,asbecauseIwantto
learnwhatittakestosolvetheproblem.OnceIvesolvedittomy
ownsatisfaction(and,sometimes,wrienaboutitsoIunderstand
howitworkswell),thenIcanappreciateamoreelegantor
generalsolution,andchuckmyown.Illhavetolookinto
boost.preprocessortoseeifitsolvestheproblemIwasseeingin
theintentcodebase;ifso,Illgladlyswitchover,sinceImalready
usingboostafairamount.
REPLY MON,JAN5,2015AT6:57PM

BLOGATWORDPRESS.COM.

https://codecraft.co/2014/11/25/variadicmacrostricks/

7/7

You might also like