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.
Related
I'm trying to build the WolfSSL, using GNU-C 7.3.1 for ARMv7.
I am getting an error where I've never seen one before. In this code fragment for Wolfio.h:
#ifndef WOLFSSL_NO_SOCK
#ifndef XSOCKLENT
#ifdef USE_WINDOWS_API
#define XSOCKLENT int
#else
#define XSOCKLENT socklen_t
#endif
#endif
/* Socket Addr Support */
#ifdef HAVE_SOCKADDR
#ifndef HAVE_SOCKADDR_DEFINED
The 6th line in the above fragment:
#define XSOCKLENT socklen_t
Gives the error:
wolfio.h:383:31: error: unknown type name 'socklen_t'; did you mean '__socklen_t'?
Huh...?? why would a #define assignment need a type that exists?
I tried an alternate test in a dummy file of a different project, with the following. Neither of which are defined:
#define MYTYPE SOMETHING
And I received no error.
Because for decades I've believed that #defines are just preprocessor replacements. And doesn't analyze any of the source. My test in the dummy file confirms that belief.
So, somehow inside this large project, the GNU compiler got into it's head that a #define is really just a typedef?? And the RHS of the #define is required to be a defined type?
Is there a compiler or #pragma setting that makes it think this?
The project is for a TI ARM device, using their Code Composer studio
For reference, the compile args are (without my includes):
-mcpu=cortex-a8
-march=armv7-a
-mtune=cortex-a8
-marm
-mfloat-abi=hard
-mfpu=neon
-Dam3359
-Dam335x
-Dxdc_target_types__=gnu/targets/std.h
-Dxdc_target_name__=gnu/targets/arm/A8F
{includes}
-Ofast
-Wall
-specs="nosys.specs"
Any advice is appreciated.
#define does not care about any types as preprocessor only textually replaces strings (more precise tokens) and does not know anything about the C language and types.
The error is generated by the C compiler when the C file after the preprocessing was compiled (ie all XSOCKLENT tokens were replace by the socklen_t token).
I think this is just a misunderstanding caused by the compiler's error message format.
You are quite right that there is nothing wrong per se with defining a macro that expands to a nonexistent type. The issue is almost certainly that some other part of your program includes this header and declares a XSOCKLENT my_var; without having included <sys/socket.h> to get the socklen_t type defined. That would account for the unknown type name error.
What's confusing you is that the line number referenced by the error message is the definition of the XSOCKLENT macro. This is a feature; the idea being that when code resulting from macro expansion causes an error, then more often than not, the bug is in the way the macro was defined. Here, that happens to not be the case. But if you look at the next bit of the compiler output, you ought to see the file and line where the macro was used. That should be the file that needs to be including <sys/socket.h>. (Or maybe you want Wolfio.h to include it; you'll have to see what makes the most sense.)
Example: with the file
#define FOO djewiodjwoidjeiwojdiwe
FOO x;
GCC 11 outputs:
foo.c:1:13: error: unknown type name ‘djewiodjwoidjeiwojdiwe’
1 | #define FOO djewiodjwoidjeiwojdiwe
| ^~~~~~~~~~~~~~~~~~~~~~
foo.c:3:1: note: in expansion of macro ‘FOO’
3 | FOO x;
| ^~~
Note the first message points to line 1, where the macro is defined, and the second part of the message points to line 3, where it is used. If one isn't what you are looking for, then try the other.
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.
This question already has answers here:
C macro to enable and disable code features
(6 answers)
Closed 7 years ago.
Background
I have C project which has a configuration header file, for example:
// config.h
#define FEATURE_1_AVAILABLE 1
#define FEATURE_2_AVAILABLE 0
#define FEATURE_3_AVAILABLE 1
Modules use these flags to include/exclude features from build:
#include "config.h"
void foo(void) {
...
#if FEATURE_1_AVAILABLE
useFeature1();
#endif
...
There are different versions of config.h for different builds.
Problem
#include "config.h" got accidentally removed, so feature wasn't active even when it was enabled in config.
Unfortunately #if FEATURE_1_AVAILABLE silently evaluates to 0 when it's not defined. So I need an error if it's not defined.
Option 1
I could add extra 'if defined' test on each condition.
#ifndef FEATURE_1_AVAILABLE
#error No feature 1
#elif FEATURE_1_AVAILABLE
useFeature1();
#endif
Downside is that one feature flag may be tested in many different places in module, and adding multiple preprocessor lines is not going to make code prettier.
Option 2
Add single test at the beginning of the module:
#ifndef FEATURE_1_AVAILABLE
#error No feature 1
#endif
But this can be lost/forgotten for the same reasons that #include "config.h" was.
Option 3
Define flags as macros:
#define FEATURE_1_AVAILABLE() 1
and use as:
#if FEATURE_1_AVAILABLE()
Unfortunaltely this will also fail silently, if you forget the parenthesis:
#if FEATURE_1_AVAILABLE
Option X
Is there a better option? Something that will give error message at compile time if symbol is not defined or is incorrectly written. And hopefully doesn't make code look unmaintainable preprocessor mess.
Other things
Runtime checks are not possible. Disabled features must not be in the binary.
Features must be defined in file. Defining them as global compiler options has other problems.
This for embedded system. Some of these features require hardware to work, and testing is very time consuming. So having errors at compile time is preferred.
Another solution is to have the compiler warn you if a macro being evaluated is not defined.
With gcc for example there is the -Wundef option (not included in -Wall):
#if FEATURE_1_AVAILABLE
useFeature1();
#endif
this gives the warning (add -Werror to make it an error):
tst.c:6:9: warning: "FEATURE_1_AVAILABLE" is not defined [-Wundef]
#if FEATURE_1_AVAILABLE
This option is also available with other compilers, e. g., clang and icc.
I know it is being frowned upon, but for smaller C projects there is nothing wrong with having one project-wide include file (say myproject.h) with all your #include .. directives (like #include "config.h") , and then have only #include "myproject.h at the top of each source file.
Accidentally forgetting this single #include will usually break the compile immediately, so that won't happen unnoticed.
Alternatively, you could put one essential #include (say #include assert.h) in your config.h (and only there), again to annoy the compiler/linker when you forget to include it
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";
In MSVC I have this in a header:
#define STR(x) #x
#define STR2(x) STR(x)
#define NOTE(text) message (__FILE__ "(" STR2(__LINE__) ") : -NOTE- " #text)
#define noteMacro(text) message (__FILE__ "(" STR2(__LINE__) ") : " STR2(text))
and I do
#pragma NOTE(my warning here)
GCC has:
#warning(my warning here)
However MSVC (2003) throws a fit when it sees #warning and gives "fatal error C1021: invalid preprocessor command 'warning'"
What can I do about this? Is there a way to have GCC recognize MSVC warnings or MSVC not throw an error on GCC warnings? Is there something I can do that works on both? I can have GCC warn me about unknown pragmas but that's not the most ideal solution.
The best solution I've found for this problem is to have the following in a common header:
// compiler_warning.h
#define STRINGISE_IMPL(x) #x
#define STRINGISE(x) STRINGISE_IMPL(x)
// Use: #pragma message WARN("My message")
#if _MSC_VER
# define FILE_LINE_LINK __FILE__ "(" STRINGISE(__LINE__) ") : "
# define WARN(exp) (FILE_LINE_LINK "WARNING: " exp)
#else//__GNUC__ - may need other defines for different compilers
# define WARN(exp) ("WARNING: " exp)
#endif
Then use
#pragma message WARN("your warning message here")
throughout the code instead of #warning
Under MSVC you'll get a message like this:
c:\programming\some_file.cpp(3) : WARNING: your warning message here
Under gcc you'll get:
c:\programming\some_file.cpp:25: note: #pragma message: WARNING: your warning message here
Not perfect, but a reasonable compromise.
As you have now discovered, #warning is not a standard feature, so you cannot use it with compilers that don't suppport it. If you want your code to work across platforms, you won't use #warning at all - or, at the least, not in code that MSVC is intended to process (it could be preprocessed out by #ifdef or equivalent). Hence:
#ifdef __GNUC__
#warning(warning message)
#else
#pragma NOTE(warning message)
#endif
But that repeats the message and I'm sure you had in mind not doing that - and it is bulky ; you'd only use it very seldom. You might also need to deal with other compilers than GCC (and I'm not familiar enough with MSVC to know how to identify it reliably).
It would be nice if #warning were standardized; it is not standardized in C99.
(There was, once upon a long time ago, an SO question about such features that could be added to C and #warning came up there.)
See also: Portability of #warning preprocessor directive
Guard them with #if statements. Look for a symbol that's defined by one compiler but not the other.
#ifdef _MSC_VER
#pragma NOTE(my warning here)
#else
#warning(my warning here)
#endif
Kind of ugly, but I don't see another way.
It is possible have code that works everywhere, and emits custom
warnings on many compilers, including most compilers people are likely
to use (GCC, clang, MSVC, Intel, ...).
First, we should distinguish between warnings and informational
messages. I think the only thing that makes sense is that, if you
compile with fatal warnings (e.g., -Werror on GCC), warnings
should cause compilation to fail, whereas informational messages
shouldn't.
As the original question mentions, MSVC 9.0+ supports
#pragma message("Hello")
Despite the (IMHO unfortunate) name, MSVC will emit a warinng here,
not an informational message. AFAICT there is no way to emit an
informational message.
GCC 4.8+ and Intel support warning message pragmas, which means we can
use the preprocessor to generate them:
#pragma GCC warning "Hello"
Note that, as of version 18, PGI does not support such warnings, even
though pgc++ masquerades as a version of GCC that should (i.e., it
sets __GNUC__, __GNUC_MINOR__, and __GNUC_PATCHLEVEL__ to values which
indicate GCC >= 4.8). They are
aware
of the issue. To get around this while still allowing some future
version of PGI which does support those to work properly, you can do
something like:
#if defined(__PGI)
# pragma diag_suppress 1675
#endif
Unfortunately I don't think there is a way to push/pop the warning
stack for PGI, so if you do this all subsequent unknown pragmas will
be silently ignored. Also, keep in mind that #pragma message is
silently ignored by PGI (it will not even generate a warning about the
pragma being unknown).
Clang also supports #pragma GCC warning (as well as #pragma clang
...), but as of 6.0 such warnings are actually informational (I've
filed a bug). I'm not sure when support was added, but clang's version
numbers are pretty useless anyways (thanks to Apple setting them to
something completely different in their clang
distribution). Unfortunately there is no __has_pragma feature test
macro, but we can temporarily disable the unknown pragma warnings so
that if the compiler doesn't support the pragma it will be silently
ignored instead of emitting an unwanted warning:
#if defined(__has_warning)
# if __has_warning("-Wunknown-pragmas")
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunknown-pragmas"
# pragma message "Hello"
# pragma clang warning "Hello"
# pragma clang diagnostic pop
# endif
#endif
Sure, it's ugly, but at least we can hide it behind a macro.
Cray 5.0+ also has a pragma for messages:
#pragma _CRI message "Hello"
I don't actually have access to Cray's compiler, so I can't be sure
about whether it is informational or a warning. If someone knows the
anwser, please comment!
Putting it all together, I recently added some macros to
Hedley to handle this, the current
version looks like this:
#if HEDLEY_HAS_WARNING("-Wunknown-pragmas")
# define HEDLEY_MESSAGE(msg) \
HEDLEY_DIAGNOSTIC_PUSH \
_Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") \
HEDLEY_PRAGMA(message msg) \
HEDLEY_DIAGNOSTIC_POP
#elif \
HEDLEY_GNUC_VERSION_CHECK(4,4,0) || \
HEDLEY_INTEL_VERSION_CHECK(16,0,0)
# define HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(message msg)
#elif HEDLEY_CRAY_VERSION_CHECK(5,0,0)
# DEFINE HEDLEY_MESSAGE(msg) HEDLEY_PRAGMA(_CRI message msg)
#else
# define HEDLEY_MESSAGE(msg)
#endif
#if HEDLEY_HAS_WARNING("-Wunknown-pragmas")
# define HEDLEY_WARNING(msg) \
HEDLEY_DIAGNOSTIC_PUSH \
_Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") \
HEDLEY_PRAGMA(clang warning msg) \
HEDLEY_DIAGNOSTIC_POP
#elif \
(HEDLEY_GNUC_VERSION_CHECK(4,8,0) && !defined(__PGI)) || \
HEDLEY_INTEL_VERSION_CHECK(16,0,0)
# define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(GCC warning msg)
#elif HEDLEY_MSVC_VERSION_CHECK(15,0,0)
# define HEDLEY_WARNING(msg) HEDLEY_PRAGMA(message(msg))
#else
# define HEDLEY_WARNING(msg) HEDLEY_MESSAGE(msg)
#endif
If you don't want to use Hedley (it's a single public domain / CC0 header for just this sort of thing) you can replace the internal macros without too much effort. If you do that, I'd suggest basing your port on the Hedley repo instead of this answer as I'm much more likely to keep it up to date.
If you wish, you can add to the above solutions a little thing (#pragma warning) before
your #pragma message:
#pragma warning()
#pragma message(" SOME USER WARNING - FILE LINE etc... ")
This little add-in generates real warning, and does not look bad in the window of VC.
For example:
1>e:\proj\file.h(19) : warning C4615: #pragma warning : unknown user warning type
1> SOME USER WARNING - FILE LINE etc...
1>proj - 0 error(s), 1 warning(s)
Usually I use this method to warnings were not too quiet, as in the case code without the #pragma warning().
For example, the form of warnings too quiet (for me of course).
1> SOME USER WARNING - FILE LINE etc..
1>proj - 0 error(s), 0 warning(s)
However, only a small cosmetics.