Is there a way to show the memory "pack" size with GCC ?
In Microsoft Visual C++, I am using:
#pragma pack(show)
which displays the value in a warning message; see Microsoft's documentation.
What is the equivalent with GCC?
Since I can't see such functionality listed in the pertinent documentation, I'm going to conclude that GCC cannot do this.
I use a static assertion whenever I pack a structure and want to see its size.
/*
The static_assert macro will generate an error at compile-time, if the predicate is false
but will only work for predicates that are resolvable at compile-time!
E.g.: to assert the size of a data structure, static_assert(sizeof(struct_t) == 10)
*/
#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(!!(COND))*2-1]
/* token pasting madness: */
#define COMPILE_TIME_ASSERT3(X,L) STATIC_ASSERT(X,at_line_##L) /* add line-number to error message for better warnings, especially GCC will tell the name of the variable as well */
#define COMPILE_TIME_ASSERT2(X,L) COMPILE_TIME_ASSERT3(X, L) /* expand line-number */
#define static_assert(X) COMPILE_TIME_ASSERT2(X, __LINE__) /* call with line-number macro */
#define PACKED __attribute__ ((gcc_struct, __packed__))
typedef struct {
uint8_t bytes[3];
uint32_t looong;
} PACKED struct_t;
static_assert(sizeof(struct_t) == 7);
This will give you a compile time warning whenever the static assertion fails.
Related
I am using gcc/g++. The below code compiles fine with gcc -S test.c, however with g++ -S test.cpp I get error: requested alignment is not an integer constant. If I look at the preprocessor output for both it looks identical. So my question is why isn't ALIGN_BYTES being evaluated to the constant 64 by the preprocessor in the C++ case? (If I replace ALIGN_BYTES with the constant 64 it works fine)
/* test.c, test.cpp */
#define BITS 512
#define ALIGN_BYTES (BITS / 8)
#define ALIGN __attribute__ ((aligned(ALIGN_BYTES)))
typedef char* ALIGN char_PT;
It is not a macro expansion issue. The macro is not expanded to a constant in either C or C++, here. The preprocessor does not do arithmetic, so it simply generates the expression 512 / 8 which isn't a constant, but which the compiler should definitely be able to reduce to one.
The preprocessor generates the same code for C and C++ here, but GCC (for reasons I do not understand) treats the __attribute__ extension differently in the two languages. I really have no idea why, there likely are good reasons, but someone else will have to explain that.
If you compile C, gcc is happy with aligned((512 / 8)), but if you compile C++ with g++ it will complain that 512 / 8 is not a constant. It is right, I guess, but really also wrong.
There are other cases where it is the opposite, where g++ is happy with a non-constant, but gcc is not. If you declare a static const int for example, you can use it in __attribute__((aligned(...)) in C++ but not in C. Again, I cannot explain why. It's a compiler extension and GCC can do whatever. And for some reason, it will treat the two languages differently here.
/* g++ will complain about this one; gcc will not */
typedef char *__attribute__((aligned((512 / 8)))) char_PT;
/* gcc will complain about this one; g++ will not */
static const int A = 16;
typedef char *__attribute__((aligned(A))) char_PT2;
I suppose, though, that since we know one version that works with C and another that works with C++, we could do this:
#define BITS 512
#ifdef __cplusplus
static const unsigned int ALIGN_BYTES = BITS / 8;
#define ALIGN __attribute__((aligned(ALIGN_BYTES)))
#else /* C */
#define ALIGN_BYTES (BITS / 8)
#define ALIGN __attribute__((aligned(ALIGN_BYTES)))
#endif
typedef char *ALIGN char_PT;
As #Deduplicator suggested, __attribute__ is a gcc extension. Using the below fixed the problem.
#ifdef __cplusplus
#define ALIGN alignas(ALIGN_BYTES)
#else
#define ALIGN __attribute__ ((aligned(ALIGN_BYTES)))
#endif
Is there a generic suppress warning that i can use?
The problem is that there are times i may build using one compiler version (gcc) and then i have a partner that uses some of the common things but uses a different compiler. So the warning # are different.
The only way i could think of doing was making a macro that was defined in a file that i would pass in some generic value:
SUPPRESS_WARNING_BEGIN(NEVER_USED)
//code
SUPPRESS_WARNING_END
then the file would have something like:
#if COMPILER_A
NEVER_USED = 245
#endif
#if COMPILER_B
NEVER_USED = 332
#endif
#define SUPPRESS_WARNING_BEGIN(x) /
#if COMPILER_A
//Compiler A suppress warning x
#endif
#if COMPILER_B
//Compiler B suppress warning x
#endif
#define SUPPRESS_WARNING_END /
#if COMPILER_A
// END Compiler A suppress warning
#endif
#if COMPILER_B
// END Compiler A suppress warning
#endif
Don't know if there is an easier way? Also i know ideally we all would just use the same compiler but that is unfortunately not an option. Just trying to find the least complicated way to support something like this and am hoping there is a simpler way then mentioned above.
thanks
There's no portable way to do that. Different compilers do it in different ways (e.g. #pragma warning, #pragma GCC diagnostic, etc.).
The easiest and best thing to do is to write code that does not generate any warnings with at compiler at any warning level.
If your goal is to suppress warnings about unused variables, I recommend using a macro:
#define UNUSED(x) ((void)sizeof(x))
...
void some_function(int x, int y)
{
// No warnings will be generated if x is otherwise unused
UNUSED(x);
....
}
The sizeof operator is evaluated at compile-time, and the cast to void produces no result, so any compiler will optimize the UNUSED statement away into nothing but consider the operand to be used.
GCC also has the unused attribute`:
// No warnings will be generated if x is otherwise unused
int x __attribute__((unused));
I ran into this today in an if and after looking into it found that all these are all valid statements that generate the C4353 . My only guess is that this is the old way of doing noop in C. Why is this not an error. When would you use this to do anything useful.
int main()
{
nullptr();
0();
(1 == 2)();
return 0;
}
Using constant 0 as a function expression is an extension that is specific to Microsoft. They implemented this specifically because they saw a reason for it, which explains why it's wouldn't make sense to treat it as an error. But since it's non-standard, the compiler emits a warning.
You are correct that it is an alternative to using __noop().
All of these :
nullptr();
0();
(1 == 2)();
are no-op statements (meaning they don't do anything).
btw I hope you are not ignoring warnings. Most of the time it is a good practice to fix all warnings.
As explained in the C4353 warning page and in the __noop intrinsic documentation, the use of 0 as a function expression instructs the Microsoft C++ compiler to ignore calls to the function but still generate code that evaluates its arguments (for side effects).
The example given is a trace macro that gets #defined either to __noop or to a print function, depending on the value of the DEBUG preprocessor symbol:
#if DEBUG
#define PRINT printf_s
#else
#define PRINT __noop
#endif
int main() {
PRINT("\nhello\n");
}
The MSDN page for that warning has ample explanation and a motivating example:
// C4353.cpp
// compile with: /W1
void MyPrintf(void){};
#define X 0
#if X
#define DBPRINT MyPrint
#else
#define DBPRINT 0 // C4353 expected
#endif
int main(){
DBPRINT();
}
As you can see it is to support archaic macro usage.
I have a Visual Studio 2008 C++ project for Windows Mobile 6 ARMV4I using Microsoft SQLCE 3.5. When I initialize the VARIANT component of a DBPROP structure (as below), I get a compiler warning message: C4366: The result of the unary '&' operator may be unaligned.
#include <sqlce_oledb.h>
DBPROP prop = { 0 };
::VariantInit( &prop.vValue ); // warning here
I can add __unaligned casts to the line, but because VariantInit doesn't take an __unaligned, I get another C4090 warning.
I notice that the DBPROP definition in *sqlce_oledb.h* includes packing directives for MIPS architecture:
#if defined(MIPSII_FP) || defined(MIPSIV) || defined(MIPSIV_FP)
#pragma pack(push,8)
#endif
typedef struct tagDBPROP
{
DBPROPID dwPropertyID;
DBPROPOPTIONS dwOptions;
DBPROPSTATUS dwStatus;
DBID colid;
VARIANT vValue;
} DBPROP;
#if defined(MIPSII_FP) || defined(MIPSIV) || defined(MIPSIV_FP)
#pragma pack(pop)
#endif
So, I can make the warning go away by doing something like this:
#define MIPSIV
#include <sqlce_oledb.h>
#undef MIPSIV
But, that feels dirty. My question is: Did the designers just overlook ARM in their packing directives (meaning I should do the dirty and claim to be a MIPS processor)? Or, should I just silence the warning and ignore it? Or, is there something else I should do?
Thanks,
PaulH
If you plan to pass the DBPROP structure to other APIs, do NOT change its alignment, since that can change the packing and it will stop working. I notice the following comment in the header:
#if 0
//DBPROPINFO is an unaligned structure. MIDL workaround. 42212352
typedef DBPROPINFO *PDBPROPINFO;
#else
typedef DBPROPINFO UNALIGNED * PDBPROPINFO; //????????????
#endif
So it seems someone was aware of a similar problem but did not change the packing, probably to avoid breaking existing code. I don't see the rest of your code from here, but you could try one of the following:
VARIANT tmp; ::VariantInit(&tmp); prop.vValue = tmp;
prop.vValue.vt = VT_EMPTY;
For example, let's say I have a function that will swap bytes in a 32 bit value for you:
uint32_t byte_swap(uint32_t in);
Well it seems silly to push that 32-bit value onto the stack and pop it off again, especially if we're going to be calling this function a lot, so let's pass it in through ECX:
#if __FASTCALL_SUPPORTED_ /* Whatever this may be */
#define FASTCALL __attribute__((fastcall))
#else
#define FASTCALL
#endif
uint32_t FASTCALL byte_swap(uint32_t in);
Now my question is, is it safe to compile that function into a shared library for distribution? If the user uses a different compiler to compile their program and links against this, will the function still be called properly?
__attribute__((fastcall)) is a gcc extension; as such, it may not be usable if the caller is not using gcc as well. Moreover, in the sample you gave, if __FASTCALL_SUPPORTED_ is not defined, you'll end up with a call with the wrong calling convention - bad idea.
One way to deal with this may be using a fallback wrapper. In your .c file:
#include "foo.h"
uint32_t FASTCALL byte_swap(uint32_t in) {
/* code ... */
}
uint32_t byte_swap__slowcall(uint32_t in) {
return byte_swap(in);
}
And in your .h file:
#if __FASTCALL_SUPPORTED_ /* Whatever this may be */
#define FASTCALL __attribute__((fastcall))
#else
#define FASTCALL
#define byte_swap byte_swap__slowcall
#endif
uint32_t FASTCALL byte_swap(uint32_t in);
Also, note that on Linux, a fast byteswap implementation is available in <byteswap.h> as bswap_32. On x86 machines, it will compile down to inline assembler, and a single instruction on high enough -march= settings.