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.
Related
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?
There is a file that I downloaded from the Unity web-site
#pragma once
// Standard base includes, defines that indicate our current platform, etc.
#include <stddef.h>
// Which platform we are on?
// UNITY_WIN - Windows (regular win32)
// UNITY_OSX - Mac OS X
// UNITY_LINUX - Linux
// UNITY_IOS - iOS
// UNITY_TVOS - tvOS
// UNITY_ANDROID - Android
// UNITY_METRO - WSA or UWP
// UNITY_WEBGL - WebGL
#if _MSC_VER
#define UNITY_WIN 1
#elif defined(__APPLE__)
#if TARGET_OS_TV //'TARGET_OS_TV' is not defined, evaluates to 0
#define UNITY_TVOS 1
#elif TARGET_OS_IOS //'TARGET_OS_IOS' is not defined, evaluates to 0
#define UNITY_IOS 1
#else
#define UNITY_OSX 1 //'UNITY_OSX' macro redefined
#endif
#elif defined(__ANDROID__)
#define UNITY_ANDROID 1
#elif defined(UNITY_METRO) || defined(UNITY_LINUX) || defined(UNITY_WEBGL)
// these are defined externally
#elif defined(__EMSCRIPTEN__)
// this is already defined in Unity 5.6
#define UNITY_WEBGL 1
#else
#error "Unknown platform!"
#endif
...
The problem is that when I try to include the file in my XCode project I got a warning (put them in comments)
...
#if TARGET_OS_TV //'TARGET_OS_TV' is not defined, evaluates to 0
#define UNITY_TVOS 1
#elif TARGET_OS_IOS //'TARGET_OS_IOS' is not defined, evaluates to 0
#define UNITY_IOS 1
#else
#define UNITY_OSX 1 //'UNITY_OSX' macro redefined
#endif
...
I tried to use #pragma warning(suppress: 4101) and a few similar approaches, but it doesn't help
UPD
...
#ifdef TARGET_OS_TV
#define UNITY_TVOS 1
#elif TARGET_OS_IOS //'TARGET_OS_IOS' is not defined, evaluates to 0
#define UNITY_IOS 1
#else
#define UNITY_OSX 1
#endif
...
Using ifdef helps to get rid of the first warning, but the second one is still in place
UPD2
...
#ifdef TARGET_OS_TV
#define UNITY_TVOS 1
#elifdef TARGET_OS_IOS //Invalid preprocessing directive
#define UNITY_IOS 1
#else
#define UNITY_OSX 1
#endif
...
You should not use #if to test an undefined macro. The warning implies that you should use #ifdef instead.
You may not define a previously defined macro. You could first undefined the old definition, but that's rarely a good idea.
Using ifdef helps to get rid of the first warning, but the second one is still in place
In c++23 you will be able to use #elifdef instead.
Otherwise, you can use #elif defined(the_macro).
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.
I used the answer from Determining 32 vs 64 bit in C++ to make this:
#ifndef AVUNA_CFG
#define AVUNA_CFG
#if _WIN32 || _WIN64
#if _WIN64
#define BIT64
#else
#define BIT32
#endif
#endif
// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__
#define BIT64
#else
#define BIT32
#endif
#endif
#endif
However, this doesn't seem to work when specifying -m32 to GCC for cross compiling, so it always says BIT64. Is there any defines I can use for this purpose?
I ended up using an Eclipse-define because I have two different run configurations for 32/64-bit cross compile. Works well.
I am converting some old code to a Visual Studio 2010 project and the following is giving me errors...
#if _MSC_VER >= 1200 || defined __BORLANDC__
#define cv_stricmp stricmp
#define cv_strnicmp strnicmp
#if defined WINCE
#define strdup _strdup
#define stricmp _stricmp
#endif
#elif defined __GNUC__ || defined __sun
#define cv_stricmp strcasecmp
#define cv_strnicmp strncasecmp
#else
#error Do not know how to make case-insensitive string comparison on this platform
#endif
I'm not sure how to adopt these statements for Visual Studio 2010. How could I do this?
I assume you don't mean the #error is hit, because that wouldn't happen with VC 2010.
If you mean the deprecation warnings, try using _stricmp and _strnicmp instead:
#if _MSC_VER >= 1200 || defined __BORLANDC__
#if _MSC_VER >= 1400
#define cv_stricmp _stricmp
#define cv_strnicmp _strnicmp
#else
#define cv_stricmp stricmp
#define cv_strnicmp strnicmp
` #endif
#if defined WINCE
#define strdup _strdup
#define stricmp _stricmp
#endif
#elif defined __GNUC__ || defined __sun
#define cv_stricmp strcasecmp
#define cv_strnicmp strncasecmp
#else
#error Do not know how to make case-insensitive string comparison on this platform
#endif