#warning and macro evaluation - c++

I have the following code :
#define LIMIT_DATE \"01-03-2010\"
#ifdef LIMIT_DATE
#if _MSC_VER
#pragma message ("Warning : this release will expire on " LIMIT_DATE)
#elif __GNUC__
#warning ("Warning : this release will expire on " LIMIT_DATE)
#endif
#endif
The problem is that LIMIT_DATE is not evaluated when printing the warning.
I searched on Google, but didn't found yet the solution.
Thanks for help.

From gcc preprocessor documentation
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.
So it's not possible at least in gcc.
According to MSDN this should work for MSVC althrough I don't have access to Visual Studio currently to test this

Related

#elseif vs #elif (C/C++ preprocessor)

I have found that writing
#ifdef ...
#elseif defined(...)
#else
#endif
always results in using either the #ifdef or the #else condition, never the #elseif. But substituting #elif causes it to work as expected based on what's defined. What convoluted purpose, if any, is served by the existence of #elseif? And if none, why doesn't the preprocessor complain?
Maybe this is why for years (decades, really), I've been using ugly #else/#endif blocks, since at least they're reliable!
#elseif is not defined. The preprocessor doesn't complain because your #ifdef is false, and the directives within that #ifdef block are not parsed. To illustrate it, this code is valid:
#if 0
#random nonsense
#else
// This must be valid
#endif
I just uncovered in IAR Embedded Workbench for MSP430, v7.11.1, which reports icc430 --version as "IAR C/C++ Compiler V7.11.1.983/W32 for MSP430",
that #elseif compiles without error, but does NOT evaluate the same as #elif.

cross platform macro for silencing unused variables warning

In porting a large piece of C++ code from Visual Studio (2008) to Xcode (4.4+), I encounter lines such as:
UNUSED_ALWAYS(someVar);
the UNUSED_ALWAYS(x) (through UNUSED(x)) macro expands to x which seems to silence Visual C++ just fine. It's not enough for Clang however.
With Clang, I usually use the #pragma unused x directive.
The UNUSED_ALWAYS and UNUSED macros are defined in an artificial windows.h header which I control that contains a number of utilities to help Xcode compile Windows stuff.
Is there a way to define UNUSED(x) to expand to #pragma unused x? I tried this, which Clang fails to accept:
#define UNUSED(x) #pragma unused(x)
I also tried:
#define UNUSED(x) (void)(x)
Which seems to work. Did I miss anything?
(void)x;
is fine; has always worked for me. You can't usually expand a macro to a #pragma, although there is usually a slightly different pragma syntax that can be generated from a macro (_Pragma on gcc and clang, __pragma on VisualC++).
Still, I don't actually need the (void)x anymore in C++, since you can simply not give a name to a function parameter to indicate that you don't use it:
int Example(int, int b, int)
{
... /* only uses b */
}
works perfectly fine.
Yup - you can use this approach for GCC and Clang:
#define MON_Internal_UnusedStringify(macro_arg_string_literal) #macro_arg_string_literal
#define MONUnusedParameter(macro_arg_parameter) _Pragma(MON_Internal_UnusedStringify(unused(macro_arg_parameter)))
although mine did have the (void) approach defined for clang, it appears that Clang now supports the stringify and _Pragma approach above. _Pragma is C99.
#define and #pragma both are preprocessor directives. You cannot define one macro to expand as preprocessor directive. Following would be incorrect:
#define MY_MACRO #if _WIN32
MY_MACRO cannot expand to #if _WIN32 for the compiler.
Your best bet is to define your own macro:
#define UNUSED(_var) _var

#warning in Visual Studio

In gcc I can do compile-time warnings like this:
#if !defined(_SOME_FEATURE_)
#warning _SOME_FEATURE_ not defined-- be careful!
#endif
But in Visual Studio this doesn't work. Is there an alternative syntax for #warning?
About the closest equivalent would be #pragma message, or possibly #error (the latter stops compilation, the former just prints out the specified error message).
Use #pragma message("Some message")
There is a good article here on how to achieve a similar effect to #warning in visual studio:
http://goodliffe.blogspot.co.uk/2009/07/c-how-to-say-warning-to-visual-studio-c.html
Edit: Here is the relevant section from the above link, however I do recommend reading the article.
#define STRINGIZE_HELPER(x) #x
#define STRINGIZE(x) STRINGIZE_HELPER(x)
#define WARNING(desc) message(__FILE__ "(" STRINGIZE(__LINE__) ") : Warning: " #desc)
// usage:
#pragma WARNING(FIXME: Code removed because...)
#pragma WEIRD_VALUES_HERE
is the way I've always seen it done. M$ probably has the pragmas on their site somewhere.
Another thought is template style compile time asserts. Boost has a whole selection of these if you are wanting to check compile time code errors.

How can I mark a C++ class method as deprecated?

I have a method in a C++ interface that I want to deprecate, with portable code.
When I Googled for this all I got was a Microsoft specific solution; #pragma deprecated and __declspec(deprecated).
If a general or fully-portable deprecation solution is not available, I will accept as a "second prize solution" one that can be used multiple specific compilers, like MSVC and a GCC.
In C++14, you can mark a function as deprecated using the [[deprecated]] attribute (see section 7.6.5 [dcl.attr.deprecated]).
The attribute-token deprecated can be used to mark names and entities whose use is still allowed, but is discouraged for some reason.
For example, the following function foo is deprecated:
[[deprecated]]
void foo(int);
It is possible to provide a message that describes why the name or entity was deprecated:
[[deprecated("Replaced by bar, which has an improved interface")]]
void foo(int);
The message must be a string literal.
For further details, see “Marking as deprecated in C++14”.
This should do the trick:
#ifdef __GNUC__
#define DEPRECATED(func) func __attribute__ ((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED(func) __declspec(deprecated) func
#else
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#define DEPRECATED(func) func
#endif
...
//don't use me any more
DEPRECATED(void OldFunc(int a, float b));
//use me instead
void NewFunc(int a, double b);
However, you will encounter problems if a function return type has a commas in its name e.g. std::pair<int, int> as this will be interpreted by the preprocesor as passing 2 arguments to the DEPRECATED macro. In that case you would have to typedef the return type.
Edit: simpler (but possibly less widely compatible) version here.
Here's a simplified version of my 2008 answer:
#if defined(__GNUC__) || defined(__clang__)
#define DEPRECATED __attribute__((deprecated))
#elif defined(_MSC_VER)
#define DEPRECATED __declspec(deprecated)
#else
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
#define DEPRECATED
#endif
//...
//don't use me any more
DEPRECATED void OldFunc(int a, float b);
//use me instead
void NewFunc(int a, double b);
See also:
MSVC documentation for __declspec(deprecated)
GCC documentation for __attribute__((deprecated))
Clang documentation for __attribute__((deprecated))
In GCC you can declare your function with the attribute deprecated like this:
void myfunc() __attribute__ ((deprecated));
This will trigger a compile-time warning when that function is used in a .c file.
You can find more info under "Diagnostic pragmas" at
http://gcc.gnu.org/onlinedocs/gcc/Pragmas.html
Here is a more complete answer for 2018.
These days, a lot of tools allow you to not just mark something as deprecated, but also provide a message. This allows you to tell people when something was deprecated, and maybe point them toward a replacement.
There is still a lot of variety in compiler support:
C++14 supports [[deprecated]]/[[deprecated(message)]].
__attribute__((deprecated)) is supported by GCC 4.0+ and ARM 4.1+
__attribute__((deprecated)) and __attribute__((deprecated(message))) is supported for:
GCC 4.5+
Several compilers which masquerade as GCC 4.5+ (by setting __GNUC__/__GNUC_MINOR__/__GNUC_PATCHLEVEL__)
Intel C/C++ Compiler going back to at least 16 (you can't trust __GNUC__/__GNUC_MINOR__, they just set it to whatever version of GCC is installed)
ARM 5.6+
MSVC supports __declspec(deprecated) since 13.10 (Visual Studio 2003)
MSVC supports __declspec(deprecated(message)) since 14.0 (Visual Studio 2005)
You can also use [[gnu::deprecated]] in recent versions of clang in C++11, based on __has_cpp_attribute(gnu::deprecated).
I have some macros in Hedley to handle all of this automatically which I keep up to date, but the current version (v2) looks like this:
#if defined(__cplusplus) && (__cplusplus >= 201402L)
# define HEDLEY_DEPRECATED(since) [[deprecated("Since " #since)]]
# define HEDLEY_DEPRECATED_FOR(since, replacement) [[deprecated("Since " #since "; use " #replacement)]]
#elif \
HEDLEY_GCC_HAS_EXTENSION(attribute_deprecated_with_message,4,5,0) || \
HEDLEY_INTEL_VERSION_CHECK(16,0,0) || \
HEDLEY_ARM_VERSION_CHECK(5,6,0)
# define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since)))
# define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement)))
#elif \
HEDLEY_GCC_HAS_ATTRIBUTE(deprcated,4,0,0) || \
HEDLEY_ARM_VERSION_CHECK(4,1,0)
# define HEDLEY_DEPRECATED(since) __attribute__((__deprecated__))
# define HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))
#elif HEDLEY_MSVC_VERSION_CHECK(14,0,0)
# define HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since))
# define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement))
#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0)
# define HEDLEY_DEPRECATED(since) _declspec(deprecated)
# define HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated)
#else
# define HEDLEY_DEPRECATED(since)
# define HEDLEY_DEPRECATED_FOR(since, replacement)
#endif
I'll leave it as an exercise to figure out how to get rid of the *_VERSION_CHECK and *_HAS_ATTRIBUTE macros if you don't want to use Hedley (I wrote Hedley largely so I wouldn't have to think about that on a regular basis).
If you use GLib, you can use the G_DEPRECATED and G_DEPRECATED_FOR macros. They're not as robust as the ones from Hedley, but if you already use GLib there is nothing to add.
Dealing with portable projects it's almost inevitable that you at some point need a section of preprocessed alternatives for a range of platforms. #ifdef this #ifdef that and so on.
In such a section you could very well conditionally define a way to deprecate symbols. My preference is usually to define a "warning" macro since most toolchains support custom compiler warnings. Then you can go on with a specific warning macro for deprecation etc.
For the platforms supporting dedicated deprecation methods you can use that instead of warnings.
For Intel Compiler v19.0, use this as __INTEL_COMPILER evaluates to 1900:
# if defined(__INTEL_COMPILER)
# define DEPRECATED [[deprecated]]
# endif
Works for the following language levels:
C++17 Support (/Qstd=c++17)
C++14 Support (/Qstd=c++14)
C++11 Support (/Qstd=c++11)
C11 Support (/Qstd=c11)
C99 Support (/Qstd=c99)
The Intel Compiler has what appears a bug in that it does not support the [[deprecated]] attribute on certain language elements that all other compilers do. For an example, compile v6.0.0 of the (remarkly superb) {fmtlib/fmt} library on GitHub with Intel Compiler v19.0. It will break. Then see the fix in the GitHub commit.

Portability of #warning preprocessor directive

I know that the #warning directive is not standard C/C++, but several compilers support it, including gcc/g++. But for those that don't support it, will they silently ignore it or will it result in a compile failure? In other words, can I safely use it in my project without breaking the build for compilers that don't support it?
It should be noted that MSVC uses the syntax:
#pragma message ( "your warning text here" )
The usual #warning syntax generates a fatal error
C1021: invalid preprocessor command 'warning'
so it is not portable to those compilers.
It is likely that if a compiler doesn't support #warning, then it will issue an error. Unlike #pragma, there is no recommendation that the preprocessor ignore directives it doesn't understand.
Having said that, I've used compilers on various different (reasonably common) platforms and they have all supported #warning.
You are likely to get at least an unrecognized directive warning from compilers that don't recognize #warning, even if the code block is not included in your compilation. That might or might not be treated as an error - the compiler could legitimately treat it as an error, but many would be more lax.
Are you aware of (can you name) a compiler other than GCC/G++ that provides #warning?
[Edited: Sun Solaris 10 (Sparc) and the Studio 11 C/C++ compilers both accept #warning.]
When switching from mingw to visual studio, I added such lines to my global config header. (include it in stdafx.h)
#ifdef __GNUC__
//from https://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html
//Instead of put such pragma in code:
//#pragma GCC diagnostic ignored "-Wformat"
//use:
//PRAGMA_GCC(diagnostic ignored "-Wformat")
#define DO_PRAGMA(x) _Pragma (#x)
#define PRAGMA_GCC(x) DO_PRAGMA(GCC #x)
#define PRAGMA_MESSAGE(x) DO_PRAGMA(message #x)
#define PRAGMA_WARNING(x) DO_PRAGMA(warning #x)
#endif //__GNUC__
#ifdef _MSC_VER
/*
#define PRAGMA_OPTIMIZE_OFF __pragma(optimize("", off))
// These two lines are equivalent
#pragma optimize("", off)
PRAGMA_OPTIMIZE_OFF
*/
#define PRAGMA_GCC(x)
// https://support2.microsoft.com/kb/155196?wa=wsignin1.0
#define __STR2__(x) #x
#define __STR1__(x) __STR2__(x)
#define __PRAGMA_LOC__ __FILE__ "("__STR1__(__LINE__)") "
#define PRAGMA_WARNING(x) __pragma(message(__PRAGMA_LOC__ ": warning: " #x))
#define PRAGMA_MESSAGE(x) __pragma(message(__PRAGMA_LOC__ ": message : " #x))
#endif
//#pragma message "message quoted"
//#pragma message message unquoted
//#warning warning unquoted
//#warning "warning quoted"
PRAGMA_MESSAGE(PRAGMA_MESSAGE unquoted)
PRAGMA_MESSAGE("PRAGMA_MESSAGE quoted")
#warning "#pragma warning quoted"
PRAGMA_WARNING(PRAGMA_WARNING unquoted)
PRAGMA_WARNING("PRAGMA_WARNING quoted")
Now I use PRAGMA_WARNING(this need to be fixed)
Sadly there is no #pragma warning in gcc, so it warns unspecified pragma.
I doubt that gcc will add #pragma warning" rather than microsoft adding #warning.
I had this problem once with a compiler for an Atmel processor. And it did generate preprocessor errors due to the unknown #warning token.
Unfortunately the solution seemed to be to convert the whole source tree to use the #pragma equivalent and accept that the build behavior was going to differ if using gcc.
Actually most compilers that I know about ignore unknown #pragma directives, and output a warning message - so in the worst case, you'll still get a warning.