I am trying to create a "single line comment" macro in C, this is used conditionally to comment out lines of codes, according to some global macro definitions. It is the same idea expressed in this article.
Trying many permutations of this code, I keep getting error messages from the compiler.
For example, directly following the code sample from that page:
#define COMMENT SLASH(/)
#define SLASH(s) /##s
#define DEBUG_ONLY COMMENT
DEBUG_ONLY a = b; // <-- line #83
GCC gives the following error:
prog.c:83:1: error: pasting "/" and "/" does not give a valid preprocessing token
prog.c:83: error: expected expression before ‘/’ token
As mentioned, I played with that theme and tried many variations but all fail giving similar diagnostics.
What am I doing wrong, and why doesn't the code from the article compiles well?
It doesn't work because the language specification doesn't allow it. In effect, comment removal happens before macro replacement. Once comments have been removed, // is not a valid token (like the error message says). It can't be generated by macro replacement, and it no longer means "comment".
This is "Translation phases" in the standard. The section numbering differs, but all of C89, C99 and C11 define in phase 3:
Each comment is replaced by one space character.
and then in phase 4:
macro invocations are expanded
A debug macro:
#define DEBUG(x) x
Which can be turned off in production as:
#define DEBUG(x)
Or IIRC #undef (sorry, my C is rusty).
Why not simply just use e.g.
#ifdef DEBUG
a = b;
#endif /* DEBUG */
Less trouble, and just as readable.
With a #define macro, you can't comment out an entire line per se, but you can comment out everything up to the next semi-colon. I find that this method works pretty well.
#define LOG_LVL 111100011
// 987654321
#if(LOG_LVL%10 >= 1 )
#define LOG1 if(1)
#else
#define LOG1 if(0)
#endif//End LOG1 if-block
#if(LOG_LVL%1000 >= 100)
#define LOG3 if(1)
#else
#define LOG3 if(0)
#endif//End LOG3 if-block
As long as you are careful with your semicolons, this should work fine. By default a non-braced if statement will only execute the following line.
The other benefit of doing logging like this is that you can fine tune what level of logging you want. In this example LOG1 is enabled and LOG3 is disabled. If i wanted my logging to be more verbose, i can quickly change LOG_LVL 111100011 to have a 1 (or higher) in it's 3 digit so that LOG3 will be enabled.
I used #define cout(x) //cout<<x; for my applications. You may want to modify it like
#ifdef DEBUG
#define cout(x) cout<<x;
#else
#define cout(x)
And use it as
cout(arg0<<arg1<<arg2);
Here, you won't be commenting the line and thus won't need separate line for avoiding print.
Further you can use cout wherever printing has to be done unconditionally.
cout("Print this when debugging");
cout<<"Always print this";
Related
I have a code which uses #warning a lot to signal compile time branches to the user. The code has a lot of configuration option, therefore it is not really clear which bits of the code are actually taken into the compilation.
Once you have chosen the configuration options, those warnings really clutter the output. So I would like to be able to disable them. The easiest way would be wrapping each of those warnings into an #ifdef ... #else construct. But if I was to touch that code again, I need to go through the whole codebase again.
So instead I want to abstract this a bit. However, I am stuck trying to define a macro that calls #warning or #pragma message. The following compiles but does not do the right thing:
#ifdef EMIT_WARNINGS
#define WARNING(s) _Pragma("message(\"Hi\")")
#else
#define WARNING(s)
#endif
WARNING("How can I print this?")
All my attempts of putting s into there have failed. Once I do _Pragma("message(\"" s "\")"), I get that _Pragma expects a single parenthesised string.
Is there anything I can do to abstract this nicely?
All my attempts of putting s into there have failed. Once I do _Pragma("message(\"" s "\")"), I get that _Pragma expects a single parenthesised string.
_Pragma(S) has an effect equivalent to #pragma X, where X is the unstringified form of S. Going backwards, that means that to get the effect of #pragma X in a _Pragma call, you simply need to stringify X.
The fact that part of X is itself a string is misleading you... don't think of these as pieces you're assembling, but rather as a whole. Rather than trying to stringify s and put it inside "message(\"" and "\")", just stringify message(s) itself as a whole, like this:
#ifdef EMIT_WARNINGS
#define WARNING_I(s) _Pragma(#s)
#define WARNING(s) WARNING_I(message(s))
#else
#define WARNING(s)
#endif
WARNING("How can I print this?")
So when warnings are enabled, WARNING("How can I print this?") expands to WARNING_I(message("How can I print this")). That argument to WARNING_I is itself what you would put on a pragma line; it is your X. The definition of WARNING_I then stringifies that, making the correct S for _Pragma.
From https://gcc.gnu.org/onlinedocs/gcc-6.3.0/cpp/Diagnostics.html#Diagnostics
Neither ‘#error’ nor ‘#warning’ macro-expands its argument. Internal whitespace sequences are each replaced with a single space. The line must consist of complete tokens. It is wisest to make the argument of these directives be a single string constant; this avoids problems with apostrophes and the like.
I'm troubleshooting a bit of code that requires a certain version of OpenSSL. If the version number exported by OpenSSL isn't high enough, a warning is returned, and various bits of the program are turned off.
The code looks like this:
#if OPENSSL_VERSION_NUMBER >= 0x10002000
//code here
#else
#warning "http_auth_ldap: Compiling with OpenSSL < 1.0.2, certificate verification will be unavailable"
Now, say that I wanted to include the reported version number in this message for the benefit of the user.
The docs for CPP say that:
Neither #error nor #warning macro-expands its argument. Internal whitespace sequences are each replaced with a single space. The line must consist of complete tokens. It is wisest to make the argument of these directives be a single string constant; this avoids problems with apostrophes and the like.
This appears to preclude me from just sticking #OPENSSL_VERISON_NUMBER onto the end of the message.
The author of this bit of code tried a stringification method detailed in this question, but it appears to not work:
#// used for manual warnings
#define XSTR(x) STR(x)
#define STR(x) #x
This leads to a warning reading:
warning: http_auth_ldap: Compiling with OpenSSL < 1.0.2, certificate verification will be unavailable. OPENSSL_VERSION_NUMBER == OPENSSL_VERSION_NUMBER [-W#pragma-messages]
..and a build failure. #pragma message appears to suffer from the same no-macro-expansion limitation as #warning.
Is there a sane way to concatenate the version string into the error?
Since #warrning is not portable, you can try to exploit other things you know about your implementation.
#define cat(a,b) cat2(a,b)
#define cat2(a,b) a##b
#define FOO 199
#define REQUIRED_FOO 200
#if FOO < REQUIRED_FOO
void cat(cat(FOO_is_, FOO),
cat(_required_FOO_is_, REQUIRED_FOO))()
{
#warning Busted!
}
#endif
Demo.
Here I exploit the fact that gcc prints the name of the function (after macro expansion!) where the error or warning happens.
For debug logging, I have often seen and used something like
#ifdef DEBUG
#define DLOG(fmt, args...) printf("%s:%d "fmt,__FILE__,__LINE__,args)
#else
#define DLOG(fmt, args...)
#endif
but in a number of places, I have seen the second #define replaced with
#define DLOG(fmt, args...) do {} while (0)
In particular, there's this answer, and the comment on this other answer to the same question suggests that the problem would be in a situation like
if (condition)
DLOG("foo");
though my quick test suggests that the resulting semicolon on the line by itself will serve as the no-op statement inside the conditional.
Is one or the other of nothing and do {} while (0) better? If so, why? Is there something else that's even better?
A semicolon by itself has two drawbacks:
Users of your macro can write it without a semicolon, and the compiler will not complain, and
Some compilers may issue a warning about a possibly stray semicolon.
The do {} while (0) trick addresses both these concerns:
DLOG("foo") // No semicolon
will trigger an error, and the compiler will not warn you about a "stray" semicolon.
See C #define macro for debug printing for an explanation of why you want a different form of no-op. You want to have the compiler parse the debug printing code even when you aren't using it so that errors do not creep in.
The quick answer is that the do/while method lets you have a multi-statement replacement and still use it as a single statement in an if case like you have in your question. For a single expression replacement, I don't think there's any difference.
What I'm trying to figure out is if something such as this (written in C):
#define FOO 15
#define BAR 23
#define MEH (FOO / BAR)
is allowed? I would want the preprocessor to replace every instance of
MEH
with
(15 / 23)
but I'm not so sure that will work. Certainly if the preprocessor only goes through the code once then I don't think it'd work out the way I'd like.
I found several similar examples but all were really too complicated for me to understand. If someone could help me out with this simple one I'd be eternally grateful!
Short answer yes. You can nest defines and macros like that - as many levels as you want as long as it isn't recursive.
The answer is "yes", and two other people have correctly said so.
As for why the answer is yes, the gory details are in the C standard, section 6.10.3.4, "Rescanning and further replacement". The OP might not benefit from this, but others might be interested.
6.10.3.4 Rescanning and further replacement
After all parameters in the replacement list have been substituted and
# and ## processing has taken place, all placemarker preprocessing tokens are removed.
Then, the resulting preprocessing token sequence
is rescanned, along with all subsequent preprocessing tokens of the
source file, for more macro names to replace.
If the name of the macro being replaced is found during this scan of
the replacement list (not including the rest of the source file's
preprocessing tokens), it is not replaced. Furthermore, if any nested
replacements encounter the name of the macro being replaced, it is not
replaced. These nonreplaced macro name preprocessing tokens are no
longer available for further replacement even if they are later
(re)examined in contexts in which that macro name preprocessing token
would otherwise have been replaced.
The resulting completely macro-replaced preprocessing token sequence
is not processed as a preprocessing directive even if it resembles
one, but all pragma unary operator expressions within it are then
processed as specified in 6.10.9 below.
Yes, it's going to work.
But for your personal information, here are some simplified rules about macros that might help you (it's out of scope, but will probably help you in the future). I'll try to keep it as simple as possible.
The defines are "defined" in the order they are included/read. That means that you cannot use a define that wasn't defined previously.
Usefull pre-processor keyword: #define, #undef, #else, #elif, #ifdef, #ifndef, #if
You can use any other previously #define in your macro. They will be expanded. (like in your question)
Function macro definitions accept two special operators (# and ##)
operator # stringize the argument:
#define str(x) #x
str(test); // would translate to "test"
operator ## concatenates two arguments
#define concat(a,b) a ## b
concat(hello, world); // would translate to "helloworld"
There are some predefined macros (from the language) as well that you can use:
__LINE__, __FILE__, __cplusplus, etc
See your compiler section on that to have an extensive list since it's not "cross platform"
Pay attention to the macro expansion
You'll see that people uses a log of round brackets "()" when defining macros. The reason is that when you call a macro, it's expanded "as is"
#define mult(a, b) a * b
mult(1+2, 3+4); // will be expanded like: 1 + 2 * 3 + 4 = 11 instead of 21.
mult_fix(a, b) ((a) * (b))
Yes, and there is one more advantage of this feature. You can leave some macro undefined and set its value as a name of another macro in the compilation command.
#define STR "string"
void main() { printf("value=%s\n", VALUE); }
In the command line you can say that the macro "VALUE" takes value from another macro "STR":
$ gcc -o test_macro -DVALUE=STR main.c
$ ./test_macro
Output:
value=string
This approach works as well for MSC compiler on Windows. I find it very flexible.
I'd like to add a gotcha that tripped me up.
Function-style macros cannot do this.
Example that doesn't compile when used:
#define FOO 1
#define FSMACRO(x) FOO + x
Yes, that is supported. And used quite a lot!
One important thing to note though is to make sure you paranthesize the expression otherwise you might run into nasty issues!
#define MEH FOO/BAR
// vs
#define MEH (FOO / BAR)
// the first could be expanded in an expression like 5 * MEH to mean something
// completely different than the second
I am trying to compare to a defined constants in C, and I have simplified my program to the following:
#include "stdio.h"
#include "stdlib.h"
#define INVALID_VALUE -999;
int main(void)
{
int test=0;
if(test==INVALID_VALUE) //The error line..
return INVALID_VALUE;
return 0;
}
And when I use gcc to compile, it gives out error "error: expected ‘)’ before ‘;’ token".
Is there any reason that this cannot be done?
Remove the semicolon from your INVALID_VALUE definition.
Macros are replaced lexically (character-by-character) with no understanding of the syntax around them. Your macro INVALID_VALUE is set to -999;, so your if line expands the macro to:
if (test==-999;)
which is invalid C syntax.
You need to remove the ; in #define INVALID_VALUE -999;. See the fixed code.
You could have worked towards this conclusion by understanding what the error message expected ‘)’ before ‘;’ token was telling you. It's telling you that it expected to find a ) before the ; token, but from inspecting the line alone you don't see a ;. So maybe there's one in the definition of INVALID_VALUE? Look up at #define INVALID_VALUE -999; and there it is! Think it should be there, but not sure? So let's try remove it and see if it works. Success!
This page goes and explains why you shouldn't conclude a #define with a semicolon, even if it is needed in the use of the macro. It's good to learn as much as possible from your mistake so that you don't make it again. Quote:
Macro definitions, regardless of
whether they expand to a single or
multiple statements should not
conclude with a semicolon. If
required, the semicolon should be
included following the macro
expansion. Inadvertently inserting a
semicolon at the end of the macro
definition can unexpectedly change the
control flow of the program.
Another way to avoid this problem is
to prefer inline or static functions
over function-like macros.
In general, the programmer should
ensure that there is no semicolon at
the end of a macro definition. The
responsibility for having a semicolon
where needed during the use of such a
macro should be delegated to the
person invoking the macro.
The C Preprocessor Macro Language is Distinct from C
The ; in the macro definition should be removed.
This is an understandable mistake. If C were designed today, the macro language might be more integrated with the rest of C.
But on 16-bit machines in the early 1970's when C was invented, it was unwise to write an overly complicated program. It would end up useless as there would be no memory remaining to actually run the big masterpiece program, and even simple programs ran slowly.
So C was split into a rather simple macro preprocessor that was, originally, a completely separate program, and the compiler proper. The preprocessor program made no attempt to parse C beyond understanding the lexical analysis model.
When 32-bit machines took over, the preprocessor was typically integrated into the parser, but naturally the language needed to remain the same.
The semi colon at the end of
#define INVALID_VALUE -999;
Classic.
You do not need a semicolon after defining something. #define is actually a macro, and it will do an inline expansion on compile.
Thus,
#define IDENTIFIER 10;
int j = IDENTIFIER;
will expand as:
int j = 10;;
Change macro
from:
#define INVALID_VALUE -999;
to
#define INVALID_VALUE -999
Bye