Here's a program that illustrates my problem:
#include <stdio.h>
#define NUMERATOR 8
#define DENOMINATOR 2
#define QUOTIENT (NUMERATOR / DENOMINATOR)
#define ZSTR(x) XSTR(#x)
#define YSTR(x) XSTR(x)
#define XSTR(x) STR(x)
#define STR(x) #x
int main()
{
printf("QUOTIENT: %d\n", QUOTIENT);
printf("STR(QUOTIENT): %s\n", STR(QUOTIENT));
printf("XSTR(QUOTIENT): %s\n", XSTR(QUOTIENT));
printf("YSTR(QUOTIENT): %s\n", YSTR(QUOTIENT));
printf("ZSTR(QUOTIENT): %s\n", ZSTR(QUOTIENT));
return 0;
}
And here's its output:
$ gcc -g -Wall -o stringify stringify.c && ./stringify
QUOTIENT: 4
STR(QUOTIENT): QUOTIENT
XSTR(QUOTIENT): (8 / 2)
YSTR(QUOTIENT): (8 / 2)
ZSTR(QUOTIENT): "QUOTIENT"
I would like to have a the string literal "4"
passed to the compiler, but I'm losing hope. This is related to this question , but adds a level.
You can define macros that paste together their arguments and then define a (large) number of other macros that do the evaluation as kind of a table lookup:
#define DIV(X, Y) DIV_(X, Y)
#define DIV_(X, Y) DIV_##X##_##Y
#define DIV_0_1 0
#define DIV_1_1 1
#define DIV_2_1 2
:
#define DIV_8_2 4
:
This is kind of tedious, but you can easily write a little program to generate a header file with the above stuff in it and run that as part of your build process. Then you just need
#define QUOTIENT DIV(NUMERATOR, DENOMINATOR)
Note that his kind of thing only works for unsigned integers -- if you need negative numbers or floating point, it won't work
With some tricks you can implement basic arithmetic in a C99 conforming preprocessor. P99 implements arithmetic and logic for small decimal numbers. Eg
P99_IF_GT(1,0)(true)(false)
P99_ADD(3, 7)
P99_MUL(7, 2)
P99_DIV(7, 2)
would be preprocessed to something like
1
10
14
3
These macros can be processed further, stringified and everthing you like.
P99_STRINGIFY(P99_PASTE2(XXX_, P99_ADD(3, 7)))
leads to "XXX_10"
as the result of preprocessing.
The best you can do is stringify the expansion of the macro which is done with your XSTR
and YSTR
examples. Although it may compile to 4
with optimizations all the pre processor will be able see is (8 / 2)
Well, I'm a little reluctant to admit I know one way to make this work.
Attack it from the other direction. You want your compiler to see something like this.
#define QUOTIENT 4
#include <stdio.h>
int main(void)
{
printf("QUOTIENT: %d\n", QUOTIENT);
return 0;
}
How do we do that without using a literal "4" in the definition of QUOTIENT, since the macro processor won't help us? By using an additional preprocessor. Write a source file, stringify.c.awk, like this.
/* stringify.c.awk -- Source file for stringify.c
(Put build instructions here.)
*/
#define QUOTIENT NUMERATOR/DENOMINATOR
#include <stdio.h>
int main(void)
{
printf("QUOTIENT: %d\n", QUOTIENT);
return 0;
}
Write the secondary preprocessor in awk. I deliberately used a really tight regular expression. I think it's the most likely regex to fail if there are changes to the source file, and I think that's usually what you want. (I usually want to discourage cosmetic changes to the #define.)
# stringify.awk -- calculate and substitute the value for #define QUOTIENT.
BEGIN {
NUMERATOR = 8;
DENOMINATOR = 2;
}
{
if ($0~/^#define QUOTIENT NUMERATOR\/DENOMINATOR$/) {
sub(/NUMERATOR\/DENOMINATOR/, NUMERATOR/DENOMINATOR);
}
print $0;
}
Now you can build stringify.c from the stringify.c.awk file.
$ awk -f stringify.awk stringify.c.awk > stringify.c
$ gcc -Wall -o stringify stringify.c
$ ./stringify
QUOTIENT: 4
A makefile and generous comments takes a lot of the pain away.
(m4 won't help for more or less the same reasons the C preprocessor won't help.)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.