14.04.2015, 21:11
(
Last edited by Misiur; 16/04/2015 at 07:21 AM.
)
Contents
Part 1 - Covers an introduction to the pre-processor and covers some important things when writing function-like macros.
Part 2 - Explains exactly what the compiler searches for and looks at some common macro uses.
Part 3 - Describes the other directives available (beside "#define") and looks at definitions with no replacement value.
Part 4 - How to use strings with the pre-processor.
Part 5 - Alternatives to the pre-processor, multiple symbols and recursion.
Part 6 - Case Study (y_remote).
Part 7 - Macro issues and spaces.
Additional
Utilising tagof - By g_aSlice.
Future-proof string concatenation
String bug
Macros that do multiple things
Advanced "tag" macros
String Generation
Every time the mode is started that printf will format the string with (run-time) constant values - this is just a waste of time for the server when we can get the compiler to do it for us using hash (#):
Let's break this down:
That is a standard define, it will replace itself with "1":
A hash within a string will convert anything after it into a string:
Now we have lots of strings separated by spaces. These will be IMplicitly combined to form one long string as they are not separated by commas:
If this was the standard PAWN compiler you would need to EXplicitly tell it to append them:
The implicit string concatenation will work for anything prefixed by a hash (implicit strings) and anything in double quotes (explicit strings).
Is not the same as:
Both will compile but the second will only print "hi" as the compiler sees the comma as the end of the implicit string. This may be more subtle, for example:
That will convert to:
Which will compile as:
This is wrong as it will only display " V 1".
Additionally, due to the selection of string end markers you can now no longer use strings as triadic operator results:
A colon ( is not seen as the end of a string, so the compiler complains that is was expecting a string, however there is a very simple way around this:
That does not change the meaning of the code in any way but compiles. This problem does not occur at all for the explicit string concatenation in the standard PAWN compiler.
Because a close bracket is seen as the end of a string you can't do:
That will try to compile with two close brackets outside the string:
An ideal solution to this would stringify the whole of the result of the macro, regardless of context and content, but it doesn't. Note that "stringify" is the technical term for what the hash operator is doing, despite not sounding very technical!
Will print: "hellothereyou". Any spaces before or after a stringified token are ignored.
Will print exactly that:
Pre-processor macros inside strings are not evaluated, in the same way as variables are not. There used to a bug (or feature) where "%N" macro parameters were evaluated inside strings, and this was used by the original version of dcmd, however that "bug" was "fixed" - prompting the development of this alternate compiler.
To summararise - to put the value of a compile time constant in a string use hash in front of it, to put the name of a compile time constant in a string enclose it it quotes. This also works for macro parameters:
This will result in:
With the first macro parameter (%0) being stringified and the second macro parameter becoming the passed "var".
Part 1 - Covers an introduction to the pre-processor and covers some important things when writing function-like macros.
Part 2 - Explains exactly what the compiler searches for and looks at some common macro uses.
Part 3 - Describes the other directives available (beside "#define") and looks at definitions with no replacement value.
Part 4 - How to use strings with the pre-processor.
Part 5 - Alternatives to the pre-processor, multiple symbols and recursion.
Part 6 - Case Study (y_remote).
Part 7 - Macro issues and spaces.
Additional
Utilising tagof - By g_aSlice.
Future-proof string concatenation
String bug
Macros that do multiple things
Advanced "tag" macros
String Generation
- General
Code:
#define VERSION_MAJOR 1 #define VERSION_MINOR 6 #define VERSION_BUILD 2345 main() { printf("=============="); printf(" Y_Less' Mode "); printf(" V %d.%d.%d ", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD); printf("=============="); }
Code:
printf(" V " #VERSION_MAJOR "," #VERSION_MINOR "," #VERSION_BUILD " ");
Code:
VERSION_MAJOR
Code:
printf(" V " #1 "," #6 "," #2345 " ");
Code:
#1
Code:
printf(" V " "1" "," "6" "," "2345" " ");
Code:
printf(" V 1,6,2345 ");
Code:
printf(" V " ... #VERSION_MAJOR ... "," ... #VERSION_MINOR ... "," ... #VERSION_BUILD ... " ");
- Restrictions
Code:
printf("hi" ", there");
Code:
printf("hi" #, there);
Code:
#define VERSION_MAJOR 1 #define VERSION_MINOR 6 #define VERSION_BUILD 2345 #define VERSION VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD main() { printf("=============="); printf(" Y_Less' Mode "); printf(" V " #VERSION); printf("=============="); }
Code:
printf(" V " #1,6,2345);
Code:
printf(" V 1", 6, 2345);
Additionally, due to the selection of string end markers you can now no longer use strings as triadic operator results:
Code:
a = var ? "one" : "two";
Code:
a = var ? ("one") : ("two");
Because a close bracket is seen as the end of a string you can't do:
Code:
#define A (5) printf("A = " #A);
Code:
printf("A = (5"));
- Spacing
Code:
printf("hello" # there "you");
- Printing tokens
Code:
#define VERSION_MAJOR 1 #define VERSION_MINOR 6 #define VERSION_BUILD 2345 main() { printf("=============="); printf(" Y_Less' Mode "); printf(" V VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD"); printf("=============="); }
Code:
V VERSION_MAJOR,VERSION_MINOR,VERSION_BUILD
To summararise - to put the value of a compile time constant in a string use hash in front of it, to put the name of a compile time constant in a string enclose it it quotes. This also works for macro parameters:
Code:
#define PRINT(%0,%1) printf(#%0,%1) PRINT(HELLO %d, var);
Code:
printf("HELLO %d", var);