16

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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • I have merged `#ifdef _MSC_VER/GCC...` into single `PRAGMA_WARNING`, http://stackoverflow.com/a/40147989/621706 – Fantastory Oct 20 '16 at 07:28

5 Answers5

16

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.

Dwighte
  • 486
  • 4
  • 9
  • 1
    Markdown doesn't appear to want to work for me, but I wanted to add that if you're only supporting GCC versions compatible with C99, and VS2008+, you can use GCC's __Pragma keyword (ex: `__Pragma(message("WARNING: " exp))`) and MSVC's __pragma keyword (ex: `__pragma(message(FILE_LINE_LINK "WARNING: " exp))`) to shorten this up a bit further. I'm assuming that VS2008 is the minimum version supported, as that's the [first version on MSDN](http://msdn.microsoft.com/en-us/library/d9x1s805(v=vs.90).aspx) that has documentation referencing this keyword. – Charles Grunwald Dec 06 '12 at 16:36
  • If you print "warning: " instead of "WARNING: " at the beginning of the message (after FILE_LINE_LINK) it even appears in the error list as a warning! – Gombat Mar 08 '16 at 13:07
  • Regretfully, MSVC does not like it now. It seems there is not a portable way of warning now, except just using `#pragma message(…)`. – Yongwei Wu Nov 17 '18 at 05:48
6

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

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
3

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.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • You added this while I was off editing my answer and adding the inverse test ... I guess `_MSC_VER` is the counterpart of `__GNUC__`! Thanks. – Jonathan Leffler Jan 23 '09 at 07:54
  • _MSC_VER not only declares you to be in Microsoft C++, it also defines which version you're using. – Mark Ransom Jan 23 '09 at 07:58
  • Conventionally predef.sourceforge.net is a nice resource to look for identifying information for compilers, OSs, libraries and more. – 0xC0000022L Feb 11 '22 at 14:28
2

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.

nemequ
  • 16,623
  • 1
  • 43
  • 62
1

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.

3609
  • 11
  • 1
  • A simpler way to force the MSVC compiler to count/show an actual warning is to have the text **": warning: "** in the output message. – Matthew Oct 12 '15 at 16:30