Skip to content

Instantly share code, notes, and snippets.

@thwarted
Created September 17, 2014 00:17
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save thwarted/8ce47e1897a578f4e80a to your computer and use it in GitHub Desktop.
Save thwarted/8ce47e1897a578f4e80a to your computer and use it in GitHub Desktop.
a FOR_EACH C Preprocessor macro that works under both GNU CC and Visual Studio 2013/MSVC
/* all this verbosity is required for this to work reliably and predictably
* on both GCC and MSVC
*/
/* because gcc cpp doesn't recursively expand macros, so a single CALLIT
* macro can't be used in all the FE_n macros below
*/
#define FE_CALLITn01(a,b) a b
#define FE_CALLITn02(a,b) a b
#define FE_CALLITn03(a,b) a b
#define FE_CALLITn04(a,b) a b
#define FE_CALLITn04(a,b) a b
#define FE_CALLITn05(a,b) a b
#define FE_CALLITn06(a,b) a b
#define FE_CALLITn07(a,b) a b
#define FE_CALLITn08(a,b) a b
#define FE_CALLITn09(a,b) a b
#define FE_CALLITn10(a,b) a b
#define FE_CALLITn11(a,b) a b
#define FE_CALLITn12(a,b) a b
#define FE_CALLITn13(a,b) a b
#define FE_CALLITn14(a,b) a b
#define FE_CALLITn15(a,b) a b
#define FE_CALLITn16(a,b) a b
#define FE_CALLITn17(a,b) a b
#define FE_CALLITn18(a,b) a b
#define FE_CALLITn19(a,b) a b
#define FE_CALLITn20(a,b) a b
#define FE_CALLITn21(a,b) a b
/* the MSVC preprocessor expands __VA_ARGS__ as a single argument, so it needs
* to be expanded indirectly through the CALLIT macros.
* http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement
* http://stackoverflow.com/questions/21869917/visual-studio-va-args-issue
*/
#define FE_n00()
#define FE_n01(what, a, ...) what(a)
#define FE_n02(what, a, ...) what(a) FE_CALLITn02(FE_n01,(what, ##__VA_ARGS__))
#define FE_n03(what, a, ...) what(a) FE_CALLITn03(FE_n02,(what, ##__VA_ARGS__))
#define FE_n04(what, a, ...) what(a) FE_CALLITn04(FE_n03,(what, ##__VA_ARGS__))
#define FE_n05(what, a, ...) what(a) FE_CALLITn05(FE_n04,(what, ##__VA_ARGS__))
#define FE_n06(what, a, ...) what(a) FE_CALLITn06(FE_n05,(what, ##__VA_ARGS__))
#define FE_n07(what, a, ...) what(a) FE_CALLITn07(FE_n06,(what, ##__VA_ARGS__))
#define FE_n08(what, a, ...) what(a) FE_CALLITn08(FE_n07,(what, ##__VA_ARGS__))
#define FE_n09(what, a, ...) what(a) FE_CALLITn09(FE_n08,(what, ##__VA_ARGS__))
#define FE_n10(what, a, ...) what(a) FE_CALLITn10(FE_n09,(what, ##__VA_ARGS__))
#define FE_n11(what, a, ...) what(a) FE_CALLITn11(FE_n10,(what, ##__VA_ARGS__))
#define FE_n12(what, a, ...) what(a) FE_CALLITn12(FE_n11,(what, ##__VA_ARGS__))
#define FE_n13(what, a, ...) what(a) FE_CALLITn13(FE_n12,(what, ##__VA_ARGS__))
#define FE_n14(what, a, ...) what(a) FE_CALLITn14(FE_n13,(what, ##__VA_ARGS__))
#define FE_n15(what, a, ...) what(a) FE_CALLITn15(FE_n14,(what, ##__VA_ARGS__))
#define FE_n16(what, a, ...) what(a) FE_CALLITn16(FE_n15,(what, ##__VA_ARGS__))
#define FE_n17(what, a, ...) what(a) FE_CALLITn17(FE_n16,(what, ##__VA_ARGS__))
#define FE_n18(what, a, ...) what(a) FE_CALLITn18(FE_n17,(what, ##__VA_ARGS__))
#define FE_n19(what, a, ...) what(a) FE_CALLITn19(FE_n18,(what, ##__VA_ARGS__))
#define FE_n20(what, a, ...) what(a) FE_CALLITn20(FE_n19,(what, ##__VA_ARGS__))
#define FE_n21(what, a, ...) what(a) FE_CALLITn21(FE_n20,(what, ##__VA_ARGS__))
#define FE_n22(...) ERROR: FOR_EACH only supports up to 21 arguments
#define FE_GET_MACRO(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,NAME,...) NAME
#define FOR_EACH(what, ...) FE_CALLITn01(FE_GET_MACRO(_0, ##__VA_ARGS__,FE_n22,FE_n21,FE_n20,FE_n19, \
FE_n18,FE_n17,FE_n16,FE_n15,FE_n14,FE_n13,FE_n12,FE_n11,FE_n10,FE_n09,\
FE_n08,FE_n07,FE_n06,FE_n05,FE_n04,FE_n03,FE_n02,FE_n01,FE_n00), (what, ##__VA_ARGS__))
/* Test expansions
* Run as:
* cpp -D__TEST__
* and examine the output
*/
#ifdef __TEST__
Each pair of lines should match.
1: FOR_EACH(e1, one)
1: e1(one)
2: FOR_EACH(e1, one, two)
2: e1(one) e1(two)
3: FOR_EACH(e1, one, two, three)
3: e1(one) e1(two) e1(three)
4: FOR_EACH(e1, one, two, three, four)
4: e1(one) e1(two) e1(three) e1(four)
5: FOR_EACH(e1, one, two, three, four, five)
5: e1(one) e1(two) e1(three) e1(four) e1(five)
6: FOR_EACH(e1, one, two, three, four, five, six)
6: e1(one) e1(two) e1(three) e1(four) e1(five) e1(six)
7: FOR_EACH(e1, one, two, three, four, five, six, seven)
7: e1(one) e1(two) e1(three) e1(four) e1(five) e1(six) e1(seven)
8: FOR_EACH(e1, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
8: e1(a1) e1(a2) e1(a3) e1(a4) e1(a5) e1(a6) e1(a7) e1(a8) e1(a9) e1(a10) e1(a11) e1(a12) e1(a13) e1(a14) e1(a15) e1(a16) e1(a17) e1(a18) e1(a19) e1(a20)
9: FOR_EACH(e1, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21)
9: e1(a1) e1(a2) e1(a3) e1(a4) e1(a5) e1(a6) e1(a7) e1(a8) e1(a9) e1(a10) e1(a11) e1(a12) e1(a13) e1(a14) e1(a15) e1(a16) e1(a17) e1(a18) e1(a19) e1(a20) e1(a21)
a: FOR_EACH(e1, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22)
a: ERROR: FOR_EACH only supports up to 21 arguments
#endif
@micjabbour
Copy link

great work! thanks for sharing this 👍

@Ryu204
Copy link

Ryu204 commented Dec 7, 2023

Thank you so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment