summaryrefslogtreecommitdiff
path: root/md
diff options
context:
space:
mode:
Diffstat (limited to 'md')
-rw-r--r--md/writeup/c_macro_tricks.md254
1 files changed, 254 insertions, 0 deletions
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 <name-struct>
+{
+<type-name> <variable-name>;
+<type-name> <variable-name>;
+...
+...
+};
+```
+
+```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.
+
+<!--
+Correct amount of arguments is 1,3,5. If need to define more then need to
+define deeper structure of M arguments. Dont forget that macro maximum argument
+number is 64 so, with this structure you can define just 31 field of structure.
+There could be done small fix and it could support 63 arguments.
+-->
+#### 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");
+```
+
+
+