I'm using the following preprocessor definitions to disable specific warnings for different c++ compilers.
Here's the code
#if defined(_MSC_VER)
#define DISABLE_WARNING_PUSH __pragma(warning(push))
#define DISABLE_WARNING_POP __pragma(warning(pop))
#define DISABLE_WARNING(warningNumber) __pragma(warning(disable : (warningNumber)))
#define DISABLE_WARNING_DEPRECATED_FUNCTION DISABLE_WARNING(4996)
#elif defined(__GNUC__) || defined(__clang__)
#define DO_PRAGMA(X) _Pragma(#X)
#define DISABLE_WARNING_PUSH DO_PRAGMA(GCC diagnostic push)
#define DISABLE_WARNING_POP DO_PRAGMA(GCC diagnostic pop)
#define DISABLE_WARNING(warningName) DO_PRAGMA(GCC diagnostic ignored #warningName)
#define DISABLE_WARNING_DEPRECATED_FUNCTION DISABLE_WARNING(-Wdeprecated-declarations)
#else
#define DISABLE_WARNING_PUSH
#define DISABLE_WARNING_POP
#define DISABLE_WARNING_DEPRECATED_FUNCTION
#endif
These defines works for GCC and CLANG but not for MSVC compiler.
On MSVC compiler I get the following warning:
(23): warning C4081: expected ')'; found '('
You can see it here: https://godbolt.org/z/hTErEbG7W
How can I fix this warning for MSVC compiler?
Related
I am trying to define the following macro:
#if defined(_MSC_VER)
#define PRAGMA_PACK_PUSH(n) __pragma(pack(push, n))
#define PRAGMA_PACK_POP() __pragma(pack(pop))
#else
#define PRAGMA_PACK_PUSH(n) #pragma (pack(push, n))
#define PRAGMA_PACK_POP() #pragma (pack(pop))
#endif
But i get the following error on Linux -
error: '#' is not followed by a macro parameter
#define PRAGMA_PACK_PUSH(n) #pragma (pack(push, n))
and it points to the first ')' in the statment
How can i define a macro that contains a #?
Solution Update:
As stated in this thread Pragma in define macro the syntax that worked is:
#if defined(_MSC_VER)
#define PRAGMA_PACK_PUSH(n) __pragma(pack(push, n))
#define PRAGMA_PACK_POP() __pragma(pack(pop))
#else
#define PRAGMA_PACK_PUSH(n) _Pragma("pack(push, n)")
#define PRAGMA_PACK_POP() _Pragma("pack(pop)")
#endif
How can i define a macro that contains a #?
You can't (define a macro that contains a directive, that is. # can still be used in macros for stringization and as ## for token concatenation). That's why _Pragma was invented and standardized in C99. As for C++, it's definitely in the C++11 standard and presumably the later ones.
You can use it as follows:
#define PRAGMA(X) _Pragma(#X)
#define PRAGMA_PACK_PUSH(n) PRAGMA(pack(push,n))
#define PRAGMA_PACK_POP() PRAGMA(pack(pop))
With that,
PRAGMA_PACK_PUSH(1)
struct x{
int i;
double d;
};
PRAGMA_PACK_POP()
preprocesses to
# 10 "pack.c"
#pragma pack(push,1)
# 10 "pack.c"
struct x{
int i;
double d;
};
# 15 "pack.c"
#pragma pack(pop)
# 15 "pack.c"
As you can see, the _Pragmas are expanding to #pragma directives.
Since _Pragma is standard, you should be able to avoid the #ifdef here if Microsoft supports it.
clang 3.9 has added to -Wall a the warning -Wexpansion-to-defined, which produces
macro expansion producing 'defined' has undefined behaviour
in case defined is used outside an #if expression, including the case of a macro that is then used within an #if expression. For example the following code
// in some file:
#define HAS_GNU (defined(__GNUC__) && !defined(__clang__))
// possibly in another file:
#if defined(__clang__) || HAS_GNU
/* ... */
#endif
produces
test.cc:5:27: warning: macro expansion producing 'defined' has undefined behavior [-Wexpansion-to-defined]
#if defined(__clang__) || HAS_GNU
^
test.cc:3:18: note: expanded from macro 'HAS_GNU'
#define HAS_GNU (defined(__GNUC__) && !defined(__clang__))
^
test.cc:5:27: warning: macro expansion producing 'defined' has undefined behavior [-Wexpansion-to-defined]
test.cc:3:40: note: expanded from macro 'HAS_GNU'
#define HAS_GNU (defined(__GNUC__) && !defined(__clang__))
So what's the 'correct' way to do that?
You can use #if - #else macros:
#if defined(__GNUC__) && !defined(__clang__)
#define HAS_GNU 1
#else
#define HAS_GNU 0
#endif
Or, if you're willing to change the code that uses HAS_GNU, perhaps more conventional way:
#if defined(__GNUC__) && !defined(__clang__)
#define HAS_GNU
#endif
#if defined(__clang__) || defined(HAS_GNU)
If you have this kind of problem with a 3d party pod, you may find this useful
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wexpansion-to-defined"
#import <pop/POP.h>
#pragma clang diagnostic pop
I want to compile a project with a Makefile.
I have defined target for linux in one of my .h
#define LINUX_TARGET (COMPILER_GCC_4_4_1|FAMILY_LINUX|TYPE_X86)
...
#ifdef _LINUX_TARGET_
#define __linux__
#define TARGET LINUX_TARGET
...
#ifdef __linux__
#define __LINUX__
#endif
So in my Makefile I say that, I will use this target:
...
CFLAGS += -D_LINUX_TARGET_
...
Butwhen I compile i get this error :
../../../../../../../Generic/Common/Include/target_definition.h:145:0: warning: "__linux__" redefined [enabled by default]
#define __linux__
^
../../../RefFT/Float/src/LIMITOR_main_32f.c:1:0: note: this is the location of the previous definition
/*---------------------------------------------------------------------------
^
I don't understand why, beceause this works for macos or windows target...
EDIT
After Joachim Pileborg answer, what I did :
#define LINUX_TARGET (COMPILER_GCC_4_4_1|FAMILY_LINUX|TYPE_X86)
...
#ifdef _LINUX_TARGET_
#ifndef __linux__
#define __linux__
#endif
#define TARGET LINUX_TARGET
...
#ifdef __linux__
#define __LINUX__
#endif
Because __linux__ is pre-defined when building on Linux.
I am trying to pack some structs with Borland C++Builder (XE6) (in the future: bcc).
I am using a library which uses the following construct to create structs:
#ifdef _MSC_VER
#define PACKED_BEGIN __pragma(pack(push, 1))
#define PACKED
#define PACKED_END __pragma(pack(pop))
#elif defined(__GNUC__)
#define PACKED_BEGIN
#define PACKED __attribute__((__packed__))
#define PACKED_END
#endif
PACKED_BEGIN
struct PACKED {
short someSampleShort;
char sampleByte;
int sampleInteger;
} structType_t;
PACKED_END
The bcc compiler does not like the MSC __pragma, and does not like preprocessor directives inside of macros although it is described on their website:
#define GETSTD #include <stdio.h>
My Question is: Is there any possibility to use this construct with the Borland Compiler for packing a struct without using:
#pragma pack(1)
to pack every struct?
Are there any workarounds for this?
As you stated, C++Builder does not support preprocessor statements inside of macros. This is documented on Embarcadero's site:
#define (C++)
After each individual macro expansion, a further scan is made of the newly expanded text. This allows for the possibility of nested macros: The expanded text can contain macro identifiers that are subject to replacement. However, if the macro expands into what looks like a preprocessing directive, the directive will not be recognized by the preprocessor.
The reason for that is because the # character inside of a macro is reserved for the preprocessor's stringizing operator.
Some compilers, including MSVC, get around that restriction with the __pragma() compiler extension, or the C99/C++x0 _Pragma() extension. C++Builder's Windows 32bit compiler does not support either of those. However, its Windows 64bit and mobile compilers (which are all based on clang and support C++11) DO support both of them. So you can add support for those compilers in the macros like this:
#if defined(__BORLANDC__)
#if defined(__clang__)
#define PACKED_BEGIN __pragma(pack(push, 1))
#define PACKED
#define PACKED_END __pragma(pack(pop))
#else
#error Cannot define PACKED macros for this compiler
#endif
#elif defined(_MSC_VER)
#define PACKED_BEGIN __pragma(pack(push, 1))
#define PACKED
#define PACKED_END __pragma(pack(pop))
#elif defined(__GNUC__)
#define PACKED_BEGIN
#define PACKED __attribute__((__packed__))
#define PACKED_END
#else
#error PACKED macros are not defined for this compiler
#endif
If you want to support the C++Builder Windows 32bit compiler, you will have to move the logic into .h files that use #pragma for it, and then you can #include those files where needed (at least until the compiler is updated to support clang/C++11 - which Embarcadero is currently working on):
pack1_begin.h:
#if defined(__BORLANDC__)
#define PACKED_BEGIN
#define PACKED
#define PACKED_END
#pragma pack(push, 1)
#elif defined(_MSC_VER)
#define PACKED_BEGIN __pragma(pack(push, 1))
#define PACKED
#define PACKED_END __pragma(pack(pop))
#elif defined(__GNUC__)
#define PACKED_BEGIN
#define PACKED __attribute__((__packed__))
#define PACKED_END
#else
#error PACKED macros are not defined for this compiler
#endif
pack_end.h:
#if defined(__BORLANDC__)
#pragma pack(pop)
#endif
Then you can do this:
#include "pack1_begin.h"
PACKED_BEGIN
struct PACKED {
short someSampleShort;
char sampleByte;
int sampleInteger;
} structType_t;
PACKED_END
#include "pack_end.h"
If you take this approach, you can just drop PACKED_BEGIN/PACKED_END altogether:
pack1_begin.h:
#if defined(__BORLANDC__) || defined(_MSC_VER)
#define PACKED
#pragma pack(push, 1)
#elif defined(__GNUC__)
#define PACKED __attribute__((__packed__))
#else
#error PACKED macro is not defined for this compiler
#endif
pack_end.h:
#if defined(__BORLANDC__) || defined(_MSC_VER)
#pragma pack(pop)
#endif
#include "pack1_begin.h"
struct PACKED {
short someSampleShort;
char sampleByte;
int sampleInteger;
} structType_t;
#include "pack_end.h"
The standard offers one extra alternative for writing pragmas: the _Pragma operator:
#define PACKED_BEGIN _Pragma("pack(push, 1)")
#define PACKED
#define PACKED_END _Pragma("pack(pop)")
If the Borland compiler supports it, it should work.
I'm trying to do something like this:
#ifdef _MSC_VER
#define DISABLE_WARNINGS() \
#pragma warning( push, 0 )
#elif __GNUC__
#define DISABLE_WARNINGS() \
#define DISABLE_WARNINGS \
#pragma GCC diagnostic push \
#pragma GCC diagnostic ignored "-Wall"
#endif
I would like to define a single macro such as "DISABLE_WARNINGS" in my code before including 3rd party headers that produce enormous amount of warnings on W4, and also ensure the code compiles on any platform.
For example:
DISABLE_WARNINGS
#include <gtkmm/buttonbox.h>
#include <gtkmm/box.h>
#include <gtkmm/window.h>
#include <gtkmm/button.h>
ENABLE_WARNINGS
What would be the best way to achieve this with single macro?
In C99 mode, you can use _Pragma instead of #pragma:
#define DISABLE_WARNINGS \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wall\"")