From 476f8cf87a3573ba6dae1dd4ed0c5047fda6acb9 Mon Sep 17 00:00:00 2001 From: FreeArtMan Date: Sun, 8 Oct 2017 22:14:06 +0100 Subject: New article --- md/writeup/c_macro_tricks.md | 254 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 md/writeup/c_macro_tricks.md (limited to 'md/writeup') diff --git a/md/writeup/c_macro_tricks.md b/md/writeup/c_macro_tricks.md new file mode 100644 index 0000000..759cf70 --- /dev/null +++ b/md/writeup/c_macro_tricks.md @@ -0,0 +1,254 @@ +title: C macro tricks +keywords:c,macro,c11,generics + +# C macro tricks + +## GCC preprocess macros + +If you need to run just macro preprocessor without running compiler use + +```bash +gcc -E source.c +``` + +this allows to see resulting source that going to be compiled, macro errors +could be hard to debug, but this is first thing, test them before and then +be sure that everything works. Lets continue with some more deep stuff. + + +## __VA_ARGS__ keyword + + +### Single argument macros +Writting macros with single argument + +```c +#define F(X) X +``` + +#### Source + +So lets code just with one macro + +```c +#define F(X) X + +F(int main) +F((){) +F(printf("hello world\n");) +F(}) +``` + +any kind of argument can be passed to macro, and that allows to make some tricks + +#### Result +``` +int main +(){ +printf("hello world\n"); +} +``` + + +### Multi argument macro + +writting macro with multiple unamed arguments + +```c +#define F(...) __VA_ARGS__ +``` + +#### Source +```c +#define F(...) __VA_ARGS__ + +F(int main) +F((){) +F(printf("hello world\n");) +F(}) + +F(1,2,3,4,5) +``` + +Previouse example works just fine, but if add multiple arguments the __VA_ARGS__ +just prints them as a whole string + +#### Result +``` +int main +(){ +printf("hello world\n"); +} + +1,2,3,4,5 +``` + + + +### Mixing named arguments and unamed arguments + +Mixing together named and unnamed arguments + +```c +#define F(X,...) X __VA_ARGS +``` + +#### Source + +```c +#define F1(X,...) __VA_ARGS__ +#define F2(X,...) X + +F1(1,2,3,4,5) +F2(1,2,3,4,5) + +F1(int main,{my code},{more code}) +F2(int main,{my code},{more code}) +``` + +#### Result + +``` +2,3,4,5 +1 + +{my code},{more code} +int main +``` + + +## Define struct with macros + +Lets move to some more practical example lets just define macro that going to +create proper C structure. + +C structure have this kind of syntax +```block +struct +{ + ; + ; +... +... +}; +``` + +```c +#define N +#define M2(X1,X2,...) X1 X2; +#define M1(X1,X2,...) X1 X2; M2(__VA_ARGS__,N,N) +#define M(X,...) struct X {M1(__VA_ARGS__,N,N)}; +``` +Here we pass variable arguments first macro M preprocess first arguments and +pass all left-over aruments with __VA_ARGS__ to M1, M1 preprocess 2 arguments +(2nd,3rd) and pass left-over arguments to next M2 macro. + +There is small trict to make support any number of arguments, there is defined +macro N that is just empty macro, so macro M support any number of arguments +and if there is not define needed amount of arguments N is passed, and if there +is not enought arguments N is used. + + +#### Source +```c +#define N +#define M2(X1,X2,...) X1 X2; +#define M1(X1,X2,...) X1 X2; M2(__VA_ARGS__,N,N) +#define M(X,...) struct X {M1(__VA_ARGS__,N,N)}; + +M(add,int,a,int,b); + +M(dirst,int,c); +``` +#### Result +``` +struct add {int a; int b;};; + +struct dirst {int c; ;};; +``` + + +## Detect number of arguments + +There is one trick that can be used to detect number of arguments passed to +macro. This common example found in internet. There could be made some +improvment or can be added some trickery. But for now most important feature +is that it works. + +```c +#define PP_NARG(...) \ + PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) + +#define PP_NARG_(...) \ + PP_ARG_N(__VA_ARGS__) + +#define PP_ARG_N( \ + _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,_29,_30, \ + _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \ + _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \ + _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \ + _61,_62,_63, N, ...) N + +#define PP_RSEQ_N() \ + 63,62,61,60, \ + 59,58,57,56,55,54,53,52,51,50, \ + 49,48,47,46,45,44,43,42,41,40, \ + 39,38,37,36,35,34,33,32,31,30, \ + 29,28,27,26,25,24,23,22,21,20, \ + 19,18,17,16,15,14,13,12,11,10, \ + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 +``` + +#### Source +```c +#define F(...) PP_NARG(__VA_ARGS__) + +F(0) +F() +F(1,2,3,4,5) +``` + +#### Result +``` +1 +1 +5 +``` + + +## Variable argument macro match macro according number of arguments + +Detect number of arguments and match macro according to number of arguments + +``` +#define FUN3(X1,X2,X3,...) "there is 3" +#define FUN2(X1,X2,...) "there is 2" +#define FUN1(X1,...) "there is 1" +#define FUNN(X,A) X ## A +#define FUNN1(X,A) FUNN(X,A) +#define FUN(X,...) void X ( FUNN1(FUN,PP_NARG(__VA_ARGS__))(__VA_ARGS__)) +``` + +#### Source +``` +FUN(add,int a,int b); +FUN(mul,int a,int b,int c); +FUN(div,int a); +``` + +#### Result +``` +void add ( "there is 2"); +void mul ( "there is 3"); +void div ( "there is 1"); +``` + + + -- cgit v1.2.3