#include<stdio.h>
#define PRINT(A,B) printf("Value of expression %s is %*",#A,#B,(A))
int main(void){
PRINT(1+3+1,%d);
return 0;
}
How to write a macro which gets two arguments: expression and format specifier then printing expression and value of it in given format?
%d is a format string, so it needs to be in double quotes, like any other string literal. Also, use meaningful names for identifiers.
#define PRINT(expr, fmt) printf("Value of expression %s is " fmt "\n", #expr, expr)
PRINT(1+3+1, "%d");
You can get away with the preprocessor's stringification operator to turn something like %d into "%d", but it's fragile (it's very sensitive to whitespace), risk-prone (code analysis tools that don't run a preprocessor may think that the code is using the variable d or choke on a syntax error on % with no left-hand side), and most importantly, it's misleading for human readers.
As a rule of thumb, you should only use unhygienic macros (macros that depart from the syntax of the language) if you have a very good reason. Typesetting an expression for debugging purposes (#expr) is a good reason. Writing programs that are two characters shorter is a good reason only if you're entering an obfuscated programming contest.
You could try something like this;
#define PRINT(A,B) printf("Value of expression %s is "#B"\n",#A,(A))
Related
Is the following code valid/good practice in C?
int x = 1;
printf(x == 1 ? "%d second elapsed" : "%d seconds elapsed", x);
It compiles fine, so I assume it is fine (also since it is just syntactical sugar for an if-else block), but if anyone has some additional insight, I would appreciate it, thank you.
P.S., I assume the same goes for C++?
Yes!
Opinionated: After wading though tons of code written by programmers writing kernels, drivers and misc. utility programs that are usually considered "good", I think the consensus is that "it's fine". Not only is it safe - it can also be made easily readable.
A small, non-opinionated, note: Compilers are allowed to make string literals overlap. If you have two string literals, "Hello world" and "world" and compile your program will full optimization, you may find that the pointer to 'w' in "world" is actually within the "Hello world" string literal, since they are both valid, null-terminated strings. Example:
ptr1
|
V
hello world\0
^
|
ptr2
However, that optimization cannot be applied to strings like yours, since the different part is in the middle of the string literal.
I therefore suggest:
printf("%d second%s elapsed", x, x == 1 ? "" : "s");
Another opinion of mine is that doing it like this also makes it easier to read.
TL,DR: pass a string literal as the format string unless you really have no choice.
Is it valid C? Yes, sure. printf wants its first argument to be a string (a null-terminated array of characters), and it's getting it. Whatever the value of x is, this string contains exactly one printf format, which expects an int argument. And printf receives an int argument. So all is fine, as far as the C language is concerned.
Is it good practice? No. There are several advantages to passing a string literal as the format string to functions like printf, scanf, etc. If you pass a string literal, that gives the compiler (and other static analyzers) the opportunity to complain if you aren't passing correctly typed arguments. If you pass something more complex, the compiler may not be able to tell. Furthermore, passing a string literal gives the compiler more optimization opportunities: many compilers will break down printf calls into lower-level functions when the format string is constant: printf("%d seconds elapsed", x) will be compiled into something like __builtin_printf_int(x) + fputs("", stdout) (plus error checking). If the format string is variable, it has to be parsed at runtime.
In this simple example, compilers are likely to recognize that there are only two possible format strings and to perform the check and optimization. In fact, let's make the program wrong:
#include <stdio.h>
void foo(long x) {
printf(x == 1 ? "%d second elapsed" : "%d seconds elapsed", x);
}
Here's what GCC has to say about it:
a.c: In function ‘foo’:
a.c:3:23: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long int’ [-Wformat=]
printf(x == 1 ? "%d second elapsed" : "%d seconds elapsed", x);
~^
%ld
a.c:3:45: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long int’ [-Wformat=]
printf(x == 1 ? "%d second elapsed" : "%d seconds elapsed", x);
~^
%ld
You're getting two warnings, one for each of the two formats. But in more complex cases, the compiler would give up and just pass the dynamically constructed string to printf at runtime, with no opportunity to bail out if the parameters are wrong.
As long as your program hard-codes English for messages, there's a simple solution: make the pluralization a separate argument.
printf("%d second%s elapsed", x, x == 1 ? "" : "s");
This doesn't work well with internationalization, since different languages have different rules (for example some languages need the singular for 0, some have a different form for 2 and 3-or-more, some need a plural on “elapsed”, etc.). If you need internationalization, you aren't passing a constant string to printf anyway.
Say I have a printf with many parameters:
printf("%d %d %d %d", A, B, C, D);
For some reason I would like one parameter to no longer be printed, but still be listed in the parameter list (for instance for visual reason, or maybe it's a function call with a necessary side effect, etc).
Can I replace %d with a conversion letter with no output ? I don't recall such a conversion letter. Or maybe playing with the flags...?
[Edit] I just noticed that scanf has something similar (but the reverse): an assignment suppression flag '*'. for instance sscanf("123 345 678", "%i %*i %i", &a, &b) will lead to a=123 b=678
If you for some reason must change these on the fly, then keep things simple:
printf("%d ", A);
printf("%d ", B);
if(c)
printf("%d ", C);
printf("%d ", D);
You can suppress Strings (char*) arguments by specifying zero-width.
However, I know of no way to suppress numeric (int and float) values.
int main(void) {
int a=1;
char* b="hello"; // Gets Suppressed
int c=3;
printf("%d %.0s %d\n", a, b, c); // .0 means "zero-width"
return 0;
}
First of all, I agree with Radosław Cybulski's comment: Relying on side-effects is a dangerous thing. So please don't do that.
As for suppressing the printing of a parameter I think there is no built-in placeholder for that and it would probably be better to just comment out the whole printf statement and add the version without the suppressed parameter below it.
With that said there are two(not very elegant) solutions I could come up with that does something similar to what you'd like to achieve:
Method1
You could create a macro like this:
#define SUPPRESS_PRINT(x) "\0"/*x*/
This will replace the parameter with a null terminator character.
Then you can use it in your printf statement like this:
printf("%d %d %s %d", A, B, SUPPRESS_PRINT(C), D);
Notice that the placeholder for C (i.e. the suppressed parameter) had to be changed to %s that is a null terminated string in order for this "trick" to yield the desired result.
Correction:
I've enhanced the above solution thanks to jhx's awesome suggestion in the comments. Using sequential evaluation possible side-effects won't be omitted. The revised macro would look like this:
#define SUPPRESS_PRINTF_ARG(x) ((x), "")
Usage would stay the same as described above.
Method2
There is yet another, possibly simpler, solution. It is a POSIX feature not a C99 one but it would work in most scenarios I assume. It is to use a parameter field in each format placeholder. Something like this:
printf("%1$d %2$d %3$d %4$d", A, B, C, D);
Then if you'd want to omit let's say parameter C from being printed you could just delete %3$d from the format string. Thus getting this:
printf("%1$d %2$d %4$d", A, B, C, D);
This might be the simplest way to go about it.
Working principle: The parameter field ties the format placeholder to a given parameter using its ordinal number. Thus even if you remove one the rest will still print correctly.
Note: As far as my testing goes this method does not omit side-effects!
I came across the following code:
#define ERROR 0
#define WARN 1
#define INFO 2
#define DEBUG 3
extern int log_level;
char const *LEVEL_TO_STRING[] = { "ERROR", "WARN", "INFO", "DEBUG" };
#define LOG(level, s, ...) \
do \
{ \
if(level <= log_level) \
printf( "[%s] " s "\n", LEVEL_TO_STRING[level], ##__VA_ARGS__) \
} \
while(0) \
I do not understand what the s is doing outside the quotes in the printf statement. I tried searching for what this is and how it works, but I'm not sure what to look for. Could someone explain to me how this code works?
As a follow-up, is it possible to write code like the example above outside a macro? The closest I've seen to this is using format specifiers:
#define FORMAT "ld"
long num = 1000000;
printf("%" FORMAT "\n", num);
It would help to understand how these two cases work internally, and why C does not let me do something like, printf("%s" s "\n", string1, string2) as is done in the macro above.
EDIT : Not a clean dup of How does concatenation of two string literals work? because this post is specific to printf (and format specifiers) as it relates to macros. Also, there is useful information in the responses to this post that isn't available in the other.
I do not understand what the s is doing outside the quotes in the printf statement
In order to see what happens you need to recall that s is replaced with the second parameter of LOG macro in the text of the program. The only way that this could work is when s is a string literal, because C merges them. In other words, there is no difference between
"quick brown fox"
and
"quick" " brown " "fox"
These two forms of writing a string literal are equivalent.
In the same way, passing "ld" to FORMAT in
printf("%" FORMAT "\n", num);
is equivalent to
printf("%ld\n", num);
and is legal.
why C does not let me do something like, printf("%s" s "\n", string1, string2) as is done in the macro above?
Passing anything other than a string literal is illegal:
char FORMAT[] = "ld";
printf("%" FORMAT "\n", num); // <<== Does not compile
s and FORMAT in your code must be not just strings, but string literals:
#define s "[%s]"
...
printf("%s" s "\n", string1, string2); // This compiles
"[%s] " s "\n"
when s is defined as a macro ie using #define would concatenate everything together.
As the substitution happens during the preprocessing, it won't be flagged as an error. In all other cases, you should get a syntax error.
The key is the line continuation '\' at the end of the definition. The code defines a macro function LOG which does the specified logging.
Apparently the user of the macro can specify their own formatted string in s and give the arguments in ... -> ##__VA_ARGS_
I'm a bit confused about an explanation concerning macros in K&R 2nd Ed, p.90. Here is the paragraph:
Formal parameters are not replaced within quoted strings. If, however, a parameter name is preceded by a # in the replacement text, the combination will be expanded into a quoted string with the parameter replaced by the actual argument.
I'm not sure what that second sentence is saying. It goes on to explain a use for this with a "debugging print macro".
This can be combined with a string concatenation to make, for example, a debugging print macro:
#define dprint(expr) printf(#expr " = %g\n", expr);
Edit:
All the input was useful. Thank you guys.
If you define macro like this:
#define MAKE_STRING(X) #X
Then, you can do something like this:
puts(MAKE_STRING(a == b));
Which will expand into:
puts("a == b");
In the dprint() example, it is printing out a string form of the expression, as well as the expression value.
dprint(sin(x)/2);
Will expand into:
printf("sin(x)/2" " = %g\n", sin(x)/2);
String literal concatenation will treat the first parameter as a single string literal.
It is just a neat feature where you can convert a macro parameter into a string literal which mainly is useful for debugging purposes. So
dprint(x + y);
is expanded by the C preprocessor to this
printf("x + y = %g\n", x + y);
Notice how the value of the parameter expr appears both inside the string literal and also in the code generated by the macro. For this to happen you need to prefix expr with # to create a string literal.
One thing worth pointing out is that adjacent string literals are combined into a single string literal, e.g. "x + y" " = %g\n" are combined into "x + y = %g\n".
#expr is expanded into "expr". Two string literals next to each other are automatically concatenated. We can see that invoking gcc -E for dprint(test) will give the following output:
("test" " = %g\n");
This site may help. It describes how stringification can be implemented.
I'm using stringizing operator to convert parameter which may contains comma passed to a macro into string. As I know, some characters cannot be stringified – notably, the comma(,) because it is used to delimit parameters and the right parenthesis()) because it marks the end of the parameter. So I use a variadic macro to pass commas to the stringizing operator like this:
#include <stdio.h>
#define TEST 10, 20
#define MAKE_STRING(...) #__VA_ARGS__
#define STRING(x) MAKE_STRING(x)
int main()
{
printf("%s\n", STRING(TEST) );
return 0;
}
it works fine. But it occurs to me what would happen without variadic macro, so I modify the macro: #define MAKE_STRING(x) #x. It compiles fine unexpectedly in visual c++ 2008/2010, and output 10, 20 while gcc/clang give the compilation error as expected:
macro "MAKE_STRING" passed 2 arguments, but takes just 1
So my question: is the Visual c++ doing additional work or the behavior is undefined?
VS in general allows extra parameters in macros and then just drops them silently:
STRING(10, 20, 30) - still works and prints 10. This is not the case here, but it pretty much means VS don't even have the error gcc threw at you.
It's not any additional work but "merely" a difference in substitution order.
I am not sure if this will answer your question but i hope this will help you solving your problem. When defining a string constant in C, you should include it in double quotes (for spaces). Also, the # macro wrap the variable name inside double quotes so, for example, #a become "a".
#include <stdio.h>
#define TEST "hello, world"
#define MAKE_STRING(x) #x
int main()
{
int a;
printf("%s\n", TEST);
printf("%s\n", MAKE_STRING(a));
return 0;
}
I compiled this code using gcc 4.7.1 and the output is:
hello, world
a
I dunno why this has upvotes, or an answer got downvoted (so the poster deleted it) but I don't know what you expect!
#__VA_ARGS__ makes no sense, suppose I have MACRO(a,b,c) do you want "a,b,c" as the string?
http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html#Variadic-Macros
Read, that became standard behaviour, variable length arguments in macros allow what they do in variable length arguments to functions. The pre-processor operates on text!
The only special case involving # is ##, which deletes a comma before the ## if there are no extra arguments (thus preventing a syntax error)
NOTE:
It is really important you read the MACRO(a,b,c) part and what do you expect, a string "a,b,c"? or "a, b, c" if you want the string "a, b, c" WRITE THE STRING "a, b, c"
Using the # operator is great for stuff like
#define REGISTER_THING(THING) core_of_program.register_thing(THING); printf("%s registered\n",#THING);