I thought a C string can be initialized with one and only one quoted string. I just wonder how is this correct?
char const help_message [] =
"Usage: %s [options] files ...\n"
"\n"
"Options include:\n"
" --verbose -v Be verbose\n"
" --help -h Print this help message\n"
" --output -o Specify output file\n"
"\n" ;
printf (help_message, argv [0]) ;
The compiler will automatically concatenate adjacent strings.
This can be quite useful to increase readability, as in your example, or with some preprocessor functions:
#define LOG(x) printf("%s", "Logging: " x)
LOG("HeyHey");
Pretty contrived example, but gets the point across.
Adjacent string literals are concatenated, and this is useful two ways: macros which combine strings and visualizing multi-line string literals such as you have above. Compare how that code would look otherwise:
char const help_message[] = "Usage: %s [options] files ...\n\nOptions include:\n --verbose -v Be verbose\n --help -h Print this help message\n --output -o Specify output file\n\n";
Imagine trying to maintain that instead. In addition, if you use a multi-line string literal, you have to either escape newlines or deal with whatever the source code uses, which may not be '\n', and you'll have to watch your indentation carefully. All of which makes the code in your example better.
Here's an example of the macro case:
#define STRINGIZE_(v) #v
#define STRINGIZE(v) STRINGIZE_(v)
#define LOCATION __FILE__ ":" STRINGIZE(__LINE__)
#define MY_ASSERT(expr) do { \
if (!(expr)) \
some_function(LOCATION ": assertion failed in " \
__PRETTY_FUNCTION__ ": " #expr); \
} while (0)
(There are alternatives to this, such as passing separate parameters, and using the GCC-specific __PRETTY_FUNCTION__ like this is deprecated too, but the rest is handy and this is a decent "real" example, IMHO.)
Other issues brought up in that code to be aware of:
the single # is the preprocessor stringize operator (## is the other special preprocessor operator, for token pasting)
without the second stringize macro, you'll get "filename.c:__LINE__"
using do-while doesn't break if-else and requires the macro to be used as a statement rather than an expression
preventing use as an expression isn't always helpful, but it is what you want for assert-like macros
Breaking if-else example:
if (cond) MY_ASSERT(blah);
else other();
Expands to:
if (cond) do { ... } while(0);
else other();
Instead of:
if (cond) if (...) ...;
else other();
Which is the incorrect and surprising:
if (cond) {
if (...) {
...;
}
else {
other();
}
}
Because adjacent quoted strings are considered to be part of the same string by the compiler. The grammar of C specifically allows this.
Don't be confused with an array of strings:
{"xxx" ,
"yyyy",
"3534"}
What you posted is a single string.
Your initializer contains only one string literal. What looks like multiple ""-enclosed string literals will actually be merged into a single string literal at the 6-th stage of translation (after preprocessing).
Related
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_
MY_PRINT is a macro throughout the code, which just does printf.
I want to temporarily modify it to also append \n after every printf.
However, when I do this:
#define SENS_PRINT(x) printf(x); printf("\n")
MY_PRINT( "\n #%d: %c ", ++command_line_number, sensor_operation_code );
...the output is trash: #3405240: <alpha symbol>
This prints ok, but no \n at end:
#define SENS_PRINT printf
You want your macro to be able to take various arguments, just like the real printf. You can do this with variadic macros.
There's also a danger that two separate expressions aren't interpreted as the macro suggests when the macro is the only expression in a conditional code block. Think about what the macro does if you say if (flag) SENS_PRINT(...);. One way to prevent this is to wrap the macro in a do { ... } while(0) block.
A variadic macro that appends a newline to printf could look like this:
#define PRINTFLN(...) do { printf(__VA_ARGS__); puts(""); } while (0)
You can use it just like printf:
PRINTFLN("Hello %s!", "cruel world");
if (flag) PRINTFLN("%d + %d == %d", x, y, sum);
The C language lets you concatenate string literals separated by whitespace. Provided all of your calls to MY_PRINT use a string literal as their formatting argument, you can define a variadic macro which will directly append "\n" to your format string, and then apply the rest of your arguments.
Defining your macro like so
#define MY_PRINT(format, ...) printf(format "\n", __VA_ARGS__)
you will be able to directly append a newline to the formatting argument.
Using this method only one function call will be performed, but any call formatted using anything other than a string literal will cause a compile error.
The problem with function-line macros is that the preprocess treats all comma-separated arguments as arguments to the macro and not as a single argument. So your compiler should really have complained that you pass to many arguments to the macro.
A simple solution is to enclose the macro argument in parentheses:
MY_PRINT( ( "\n #%d: %c ", ++command_line_number, sensor_operation_code ) );
// ^ ^
// | |
// Note extra parentheses here... and here
Another solution is to use variadic macros.
On a somewhat related note, your macro, as you show it, can't be used in construct like e.g.
if (some_condition)
MY_PRINT(...);
That will be replaced like
if (some_condition)
printf(...);
printf(...);
If you have multiple statements inside a macro, you need to enclose it in a block, like e.g.
#define MY_PRINTF(...) \
do { \
statement1; \
statement2; \
. \
. \
. \
statementN; \
} while (0)
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've made a trivial reduction of my issue:
#define STR_BEG "
#define STR_END "
int main()
{
char * s = STR_BEG abc STR_END;
printf("%s\n", s);
}
When compiling this, I get the following error:
static2.c:12:16: error: expected expression
char * s = STR_BEG abc STR_END;
^
static2.c:7:17: note: expanded from macro 'STR_BEG'
#define STR_BEG "
Now, if I just run the preprocessor, gcc -E myfile.c, I get:
int main()
{
char * s = " abc ";
printf("%s\n", s);
}
Which is exactly what I wanted, and perfectly legal resultant code. So what's the deal?
The macro isn't really expanding "correctly", because this isn't a valid C Preprocessor program. As Kerrek says, the preprocessor doesn't quite work on arbitrary character sequences - it works on whole tokens. Tokens are punctuation characters, identifiers, numbers, strings, etc. of the same form (more or less) as the ones that form valid C code. Those defines do not describe valid strings - they open them, and fail to close them before the end of the line. So an invalid token sequence is being passed to the preprocessor. The fact it manages to produce output from an invalid program is arguably handy, but it doesn't make it correct and it almost certainly guarantees garbage output from the preprocessor at best. You need to terminate your strings for them to form whole tokens - right now they form garbage input.
To actually wrap a token, or token sequence, in quotes, use the stringification operator #:
#define STRFY(A) #A
STRFY(abc) // -> "abc"
GCC and similar compilers will warn you about mistakes like this if you compile or preprocess with the -Wall flag enabled.
(I assume you only get errors when you try to compile as C, but not when you do it in two passes, because internally to the compiler, it retains the information that these are "broken" tokens, which is lost if you write out an intermediate file and then compile the preprocessed source in a second pass... if so, this is an implementation detail, don't rely on it.)
One possible solution to your actual problem might look like this:
#define LPR (
#define start STRFY LPR
#define end )
#define STRFY(A) #A
#define ID(...) __VA_ARGS__
ID(
char * s = start()()()end; // -> char * s = "()()()";
)
The ID wrapper is necessary, though. There's no way to do it without that (it can go around any number of lines, or even your whole program, but it must exist for reasons that are well-covered in other questions).
I am trying to do the following:
#define mkstr(str) #str
#define cat(x,y) mkstr(x ## y)
int main()
{
puts(cat(\,n));
puts(cat(\,t))
return 0;
}
both of the puts statements cause error. As \n and n both are preprocessor tokens I expected output them correctly in those puts statements, but Bloodshed/DevC++ compiler giving me the following error:
24:1 G:\BIN\cLang\macro2.cpp pasting "\" and "n" does not give a valid preprocessing token
Where is the fact I'm missing?
The preprocessor uses a tokenizer which will require C-ish input. So even when stringifying you cannot pass random garbage to a macro. ==> Don't make your preprocessor sad - it will eat kittens if you do so too often.
Actually, there is no way to create "\n" via compile-time concatenation since "\\" "n" is a string consisting of the two literals, i.e. "\n".