When can I pass variable's value to a macro for stringifying?
For example the code taken from this post works with a constant-defined macro.
#define MAX_STRING_LENGTH 20
#define STRINGIFY(x) STRINGIFY2(x)
#define STRINGIFY2(x) #x
{
...
char word[MAX_STRING_LENGTH+1];
scanf("%" STRINGIFY(MAX_STRING_LENGTH) "s", word);
...
}
However I cannot use it with a variable such as:
{
...
int val = 20;
char word[MAX_STRING_LENGTH+1];
scanf("%" STRINGIFY(val) "s", word);
...
}
since the compilation is successful with this warning:
warning: invalid conversion specifier 'v' [-Wformat-invalid-specifier]
scanf("%" STRINGIFY(var) "s", word);
~~~^~~~~~~~~~~~~
test2.c:4:22: note: expanded from macro 'STRINGIFY'
#define STRINGIFY(x) STRINGIFY2(x)
^
test2.c:5:23: note: expanded from macro 'STRINGIFY2'
#define STRINGIFY2(x) #x
^
<scratch space>:466:2: note: expanded from here
"var"
^
1 warning generated
but the run of the code does not wait for any input.
On the contrary in this other post it was possible to pass a variable to this macro:
#define PRINT(int) printf(#int "%d\n",int)
...
int var =8;
PRINT(var);
What is the difference between the two cases? How can I modify the first one so that it accepts also variables?
I tried using %d inside the macro but I was not successful.
The preprocessor always operates on tokens only.
A macro is not a function. You don't pass it a variable (by value). You pass a token sequence. In STRINGIFY(MAX_STRING_LENGTH) the token sequence is MAX_STRING_LENGTH, and in STRINGIFY(val) it's the token sequence val.
MAX_STRING_LENGTH is itself a macro, and due to how STRINGIFY is defined to work, the macro will be expanded by the preprocessor before turning it a string literal. So 20 is in turn the token which gets # applied to it, and it produces "20" as a string literal.
On the other hand val is not a macro, the preprcosseor is not going to expand it. It's going to keep the token sequence as val. The fact val is the name of a variable with some value means nothing to the preprocessor, it only cares about tokens. So val is transformed into the literal "val".
The example you brought from another post worked because it expanded to this:
printf("var" "%d\n", var);
The variable name in #int turns into a literal, there is no magic that lets the preprocessor read a variable's value. The fact var 8 is printed is only because var is passed as an argument to printf! It's printed at run-time by the %d specifier.
Finally, when experimenting with the preprcoessor it's always helpful to look at the source file after prpeprocessing is done, but before the file is compiled. The gcc -E flag (or equivalent for your compiler) can help you do that.
STRINGIFY(val) will result in "val", not the value you wanted to stringify, so you get a final format string of "%vals" ("%" "val" "s"). That's how the C preprocessor works, it does just text replacements, nothing more.
The PRINT example:
#define PRINT(int) printf(#int "%d\n", int)
PRINT(var); // to be resolved
printf(#var "%d\n", var); // intermediate result
printf("var" "%d\n", var); // final result, this is what the C compiler sees
But why did it work with MAX_STRING_LENGTH?
#define MAX_STRING_LENGTH 20
#define STRINGIFY(x) STRINGIFY2(x)
#define STRINGIFY2(x) #x
STRINGIFY(MAX_STRING_LENGTH) // to be resolved
STRINGIFY2(20) // intermediate step; STRINGIFY2 known as macro, thus:
#20 // another intermediate step
"20" // final result
Related
#define Page 5
void printSystemInfo() {
printf ("%i", Page);
}
Thats my code can anyone explain me how to print Page 5 in the console?
For now my console looks like this "5" But I want to have "Page 5"
Thanks for helping !
You can use a little preprocessor trick. We have the # operator, which will convert a symbol into a string.
#define _(a) #a
When you call _(foo), it translates it as "foo". So, in your case, you could do something like:
#include <stdio.h>
#define _(a) # a
#define PAGE 5
int main(int argc, char *argv[])
{
printf("%s: %i\n", _(PAGE), PAGE);
return 0;
}
What this will do is:
We define a macro named _ that takes one parameter a. This macro uses the operator # from the preprocessor (called stringification). This will case a named passed to the macro to be converted into a string. Example: _(foo) gets translated to "foo".
In main, the printf() call is then translated as printf("%s: %i\n", "PAGE", 5);. In a stepwise way, when the preprocessor sees the _(PAGE) symbol, it translates it as "PAGE".
The inner workings of this things is explained in the above link, which I quote (my markings):
Sometimes you may want to convert a macro argument into a string constant. Parameters are not replaced inside string constants, but you can use the ‘#’ preprocessing operator instead. When a macro parameter is used with a leading ‘#’, the preprocessor replaces it with the literal text of the actual argument, converted to a string constant. Unlike normal parameter replacement, the argument is not macro-expanded first. This is called stringification.
Here you go. This is very trivial stuff, but please ask if something is unclear.
#define Page 5
void printSystemInfo()
{
printf((char const[])??<0120,0141,0147,0145,0040,0045,0151,!"bad"??>,Page);
}
Is it possible to define a macro that will trim off a portion of the string argument passed in?
For example:
//can this be defined?
#define MACRO(o) ???
int main(){
printf(MACRO(ObjectT)); //prints "Object" not "ObjectT"
}
Would it be possible for a macro that trim off the last character 'T'?
You can do it for specific strings that you know in advance, presented to the macro as symbols rather than as string literals, but not for general symbols and not for string literals at all. For example:
#include <stdio.h>
#define STRINGIFY(s) # s
#define EXPAND_TO_STRING(x) STRINGIFY(x)
#define TRUNCATE_ObjectT Object
#define TRUNCATE_MrT Pity da fool
#define TRUNCATE(s) EXPAND_TO_STRING(TRUNCATE_ ## s)
int main(){
printf(TRUNCATE(ObjectT)); // prints "Object"
printf(TRUNCATE(MrT)); // prints "Pity da fool"
}
That relies on the token-pasting operator, ##, to construct the name of a macro that expands to the truncated text (or, really, the replacement text), and the stringification operator, #, to convert the expanded result to a string literal. There's a little bit of required macro indirection in there, too, to ensure that all the needed expansions are performed.
Well, at least it should print "Object"...
//can this be defined?
#define MACRO(o) #o "\b \b"
int main(){
printf(MACRO(ObjectT)); //prints "Object" not "ObjectT"
}
And no, you can't strip character using preprocessor only without actual C code (say, malloc+strncpy) to do that.
With the preprocessor? No. It sounds like what you really want to do is something like this:
Code not tested
#define STRINGIFY(o) #o
char* serialize(char* s)
{
if (strcmp(s, "ObjectT") == 0) return "Object";
}
int main(){
printf(serialize(STRINGIFY(#o))); //prints "Object" not "ObjectT"
}
I need a function to read a file name, with a max length of MAX_FILE_NAME_SIZE, which is a symbolic constant, I did this the following way:
char * readFileName()
{
char format[6];
char * fileName = malloc(MAX_FILE_NAME_SIZE * sizeof(fileName[0]));
if(fileName== NULL)
return NULL;
sprintf(format, "%%%ds", MAX_FILE_NAME_SIZE-1);
scanf(format, fileName);
fileName= realloc(fileName, strlen(fileName)*sizeof(fileName[0]));
return fileName;
}
I'd really like to get read of the sprintf part (and also the format vector), what's the cleanest and most efficient way to do this?
Solution
You can make a little Preprocessor hack:
#define MAX_BUFFER 30
#define FORMAT(s) "%" #s "s"
#define FMT(s) FORMAT(s)
int main(void)
{
char buffer[MAX_BUFFER + 1];
scanf(FMT(MAX_BUFFER), buffer);
printf("string: %s\n", buffer);
printf("length: %d\n", strlen(buffer));
return 0;
}
The FORMAT and FMT macros are necessary for the preprocessor to translate them correctly. If you call FORMAT directly with FORMAT(MAX_BUFFER), it will translate into "%" "MAX_BUFFER" "s" which is no good.
You can verify that using gcc -E scanf.c. However, if you call it through another macro, which will effectively resolve the macro names for you and translate to "%" "30" "s", which is a fine format string for scanf.
Edit
As correctly pointed out by #Jonathan Leffler in the comments, you can't do any math on that macro, so you need to declare buffer with plus 1 character for the NULL terminating byte, since the macro expands to %30s, which will read 30 characters plus the null byte.
So the correct buffer declaration should be char buffer[MAX_BUFFER + 1];.
Requested Explanation
As asked in the comments, the one macro version won't work because the preprocessor operator # turns an argument into a string (stringification, see bellow). So, when you call it with FORMAT(MAX_BUFFER), it just stringifies MAX_BUFFER instead of macro-expanding it, giving you the result: "%" "MAX_BUFFER" "s".
Section 3.4 Stringification of the C Preprocessor Manual says this:
Sometimes you may want to convert a macro argument into a string constant. Parameters are not replaced inside string constants, but you can use the ‘#’ preprocessing operator instead. When a macro parameter is used with a leading ‘#’, the preprocessor replaces it with the literal text of the actual argument, converted to a string constant. Unlike normal parameter replacement, the argument is not macro-expanded first. This is called stringification.
This is the output of the gcc -E scanf.c command on a file with the one macro version (the last part of it):
int main(void)
{
char buffer[30 + 1];
scanf("%" "MAX_BUFFER" "s", buffer);
printf("string: %s\n", buffer);
printf("length: %d\n", strlen(buffer));
return 0;
}
As expected. Now, for the two levels, I couldn't explain better than the documentation itself, and in the last part of it there's an actual example of this specific case (two macros):
If you want to stringify the result of expansion of a macro argument, you have to use two levels of macros.
#define xstr(s) str(s)
#define str(s) #s
#define foo 4
str (foo)
==> "foo"
xstr (foo)
==> xstr (4)
==> str (4)
==> "4"
s is stringified when it is used in str, so it is not macro-expanded first. But s is an ordinary argument to xstr, so it is completely macro-expanded before xstr itself is expanded (see Argument Prescan). Therefore, by the time str gets to its argument, it has already been macro-expanded.
Resource
The C Preprocessor
I want to know if there is any way to escape macro name and actually show the real name :
#define BUFF_SIZE 500
printf("%d", BUFF_SIZE);
Is it possible to not expand BUFF_SIZE here without removing the define?
Stringification:
Sometimes you may want to convert a macro argument into a string
constant. Parameters are not replaced inside string constants, but you
can use the ‘#’ preprocessing operator instead. When a macro parameter
is used with a leading ‘#’, the preprocessor replaces it with the
literal text of the actual argument, converted to a string constant.
Unlike normal parameter replacement, the argument is not
macro-expanded first. This is called stringification.
#include <stdio.h>
#define BUFF_SIZE 500
#define STR(x) #x
int main(void)
{
printf("%s\n", STR(BUFF_SIZE));
return 0;
}
Note that you can't print a string with %d, use %s.
This question already has answers here:
Convert a preprocessor token to a string
(6 answers)
Closed 9 years ago.
There's got to be a way to do this...
I have a header file, version.h with one line...
#define VERSION 9
and a few files use the defined value of VERSION as an integer.
That's fine.
Without changing the way VERSION is defined, I need to build an
initialized "what" string that contains that value,
so I need something like this...
char *whatversion = "#(#)VERSION: " VERSION;
obviously this doesn't compile, so somehow I need to get a
string of the preprocessed value of VERSION essentially giving this...
char *whatversion = "#(#)VERSION: " "9";
Any ideas?
Is this possible?
It is not a datatype, it is a token. A blob of text.
K & R talk about concatenating values:
The preprocessor operator ## provides a way to concatenate actual arguments
during macro expansion. If a parameter in the replacement text is adjacent
to a ##, the parameter is replaced by the actual argument, the ## and
surrounding white space are removed, and the result is re-scanned. For example,
the macro paste concatenates its two arguments:
#define paste(front, back) front ## back
so paste(name, 1) creates the token name1.
-- try that. #define the string before you get to char *version=
Inside a macro, you can use the "stringify" operator (#) which will do exactly what you want:
#define STR2(x) #x
#define STR(x) STR2(x)
#define STRING_VERSION STR(VERSION)
#define VERSION 9
#include <stdio>
int main() {
printf("VERSION = %02d\n", VERSION);
printf("%s", "#(#)VERSION: " STRING_VERSION "\n");
return 0;
}
Yes, you do need the double indirection in the macro call. Without it, you'd get "VERSION" instead of "9".
You can read more about this in the gcc manual (although it is fully standard C/C++).