object won't pack data - c++

I'm trying to pack data in a c++ struct.
My struct has this layout:
struct structName
{
int16_t member1;
int32_t member2;
uint32_t member3;
uint32_t member4;
uint32_t member5;
etc
}__attribute__((packed));
Using offsetof($structname, $membername) I get back the correct offsets of the data (0,2,6,10,14 . . .), but when I access the data by member-name I get the data at 4 byte offsets (0,4,8,12,16 . . .) as if the struct wasn't packed.
Is
} __attribute__((packed));
the correct way to make a struct packed?
.
.

Update: mydogisbox wrote:
For the record, __attribute__((packed)), #pramga pack(1) and #pragma pack(push, 1) all worked.
__attribute__((packed)) is a gcc extension, which is supported.
The clang documentation says it also supports #pragma pack(...) directive:
clang has some experimental support for extensions from Microsoft
Visual C++; to enable it, use the -fms-extensions command-line option.
This is the default for Windows targets. Note that the support is
incomplete; enabling Microsoft extensions will silently drop certain
constructs (including __declspec and Microsoft-style asm statements).
clang supports the Microsoft #pragma pack feature for controlling record layout.
source: http://clang.llvm.org/docs/UsersManual.html
Just say:
#pragma pack(1)
struct my_struct {
int16_t x;
// etc.
};
to see if it works (compile with -fms-extensions if not using Windows).
Note the above are all non-standard extensions, and the new C++11 standard has a new alignas keyword: http://en.cppreference.com/w/cpp/language/alignas
struct alignas(1) my_struct {
int16_t x;
// etc.
};
but its support is still a bit sketchy.

Related

Are identically named members of unnamed structs in a union an error or a GCC bug?

The below code can be compiled successfully in Visual C++. I like it and it is sweet!
#include <stdio.h>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4201)
#pragma pack(push,1)
#define PACKED
#else
#define PACKED __attribute__ ((__packed__))
#endif
union A {
struct {
int a:1;
int b:2;
int c1:29;
}PACKED;
struct {
int a:1;
int b:2;
int c2:28;
int d:1;
}PACKED;
int val;
}PACKED;
#ifdef _MSC_VER
#pragma pack(pop)
#pragma warning(pop)
#endif
#undef PACKED
int main(){
A test;
test.val = 0x1078FFF7;
printf("sizeof(A): %d, test.a: %d.\n", sizeof(A), test.a);
return -1;
}
Output with the file built with MSC:
sizeof(A): 4, test.a: -1.
But in GCC, including the latest gcc-7, it failed to be compiled, :(
struct.cpp:13:15: error: redeclaration of ‘signed char:1 A::<unnamed struct>::a’
int a:1;
^
struct.cpp:7:15: note: previous declaration ‘signed char:1 A::<unnamed struct>::a’
int a:1;
^
struct.cpp:14:15: error: redeclaration of ‘signed char:2 A::<unnamed struct>::b’
int b:2;
^
struct.cpp:8:15: note: previous declaration ‘signed char:2 A::<unnamed struct>::b’
int b:2;
^
Is it a bug in GCC?
Thanks for your comments, I just understood this question may be invalid for C; But for C++ part, I still have the concern. Personally I like Visual C++ compile behavior, it can save tons of code in my scenario
6.7.2.1 Structure and union specifiers says:
An unnamed member whose type specifier is a structure specifier with no tag is called an anonymous structure; an unnamed member whose type specifier is a union specifier with no tag is called an anonymous union. The members of an anonymous structure or union are considered to be members of the containing structure or union. This applies recursively if the containing structure or union is also anonymous.
(emphasis mine)
So based on that, it's essentially as if you had:
union A
{
int a:1;
int b:2;
int c1:29;
int a:1;
int b:2;
int c2:28;
int d:1;
int val;
};
which would obviosuly be invalid and gcc correctly issues diagnostics.
It's not a bug in GCC.
The language standard does not allow this. But Visual C++ does, if anything to allow compilation of Windows headers. In fact, if you don't want to use a Microsoft compiler to compile Windows headers then you need to use
#define NONAMELESSUNION
before #include <windows.h>. It probably seemed like a good idea at the time.
Reference: What are anonymous structs, and more importantly, how do I tell windows.h to stop using them?
It has been discussed in P.P.'s answer and the comments, that what you want isn't correct and GCC behaves correctly. But an easy workaround which fulfills your need might be that you rename a and b in the second struct:
union A {
struct {
int a:1;
int b:2;
int c1:29;
}PACKED;
struct {
int unused_name_a:1;
int unused_name_b:2;
int c2:28;
int d:1;
}PACKED;
int val;
}PACKED;
This worked for me in GCC and Clang and should still allow your trick to work nicely.

Pragma in c++ struct in class

I have one question about using pragma in c++ classes.
I've read there (Use of #pragma pack on a class) that use pragma around c++ class is not recommended, but can I use pragma like this:
class TestClass {
public:
ConfigProtocol();
#pragma pack(1)
struct t_config_header {
quint8 version;
quint8 da;
quint16 sa;
quint16 counter;
};
#pragma pack()
};
will not it be mistake?
Short answer: Yes you can (and in your case, as it seems you are implementing a communcation protocol, in fact, should) do it.
The way you are using the pragma is only affecting the structure which invalidates the arguments made in the StackOverflow answer you are linking to: The struct is not significantly changing as long as it stays a struct.

Why g++ isn't performing structure packing here?

Consider following program:
#include <iostream>
struct __attribute__((__packed__)) mystruct_A
{
char a;
int b;
char c;
}x;
int main()
{
std::cout<<sizeof(x)<<'\n';
}
From this I understood following:
Structure packing suppresses structure padding, padding used when
alignment matters most, packing used when space matters most.
Structure Packing, on the other hand prevents compiler from doing
padding
I am on 32 bit environment & using Windows 7 OS. The 1st answer of linked question says that above code would produce structure of size 6 on a 32-bit architecture.
But when I compiled it using g++ 4.8.1 it gives me 9 as an output. So, is structure packing not happening completely here?
Why extra 3 bytes are there in output?
sizeof char is always 1. Sizeof int is 4 on my compiler. So, sizeof above struct should be 1+4+1=6 when structure is packed.
I tried it on here. It gives me expected output 6.
Is there any role of processor or it depends only on Compiler?
attribute packed is broken on mingw32 compilers. Another option is to use
pragma pack:
#pragma pack(1)
struct mystruct_A {
char a;
int b;
char c;
} x;
Solution here worked for me: https://wintermade.it/blog/posts/__attribute__packed-on-windows-is-ignored-with-mingw.html, which is to add -mno-ms-bitfields to the compiler flags.

Best way to read binary data in C++ using classes without padding

I am reading simple binary data, without pointers, using C++ classes without padding with the following code:
#include <fstream>
#include <iostream>
using namespace std;
class Data {
public:
int a;
int b;
short int c;
double d;
}__attribute__((packed));
int main() {
Data myData;
ifstream ifs("test.bin", ios::binary);
ifs.read((char *)&myData, sizeof(myData));
ifs.close();
}
I am using this method because the data might have 20+ different formats and I want to write 20+ different classes to cover all the formats that might show up. I also read that other options include using bit-fields, pragma directives, and even the boost serialization routines (I can't because I have to use std). My question is: is this the best way to read simple binary data using classes without padding? Do you suggest any other alternative? I would like to learn what is the safest and most widely used method out there.
Typically, one would use a struct instead of a class, but yes, the same concept applies to both.
I've used these macros to allow packed structs to compile on both gcc and VC:
#ifdef _MSC_VER
#define BEGIN_PACK __pragma( pack(push, 1) )
#define END_PACK __pragma( pack(pop) )
#else
#define BEGIN_PACK
#define END_PACK __attribute__((packed))
#endif
So then you'd use them like this:
BEGIN_PACK
struct Data {
int a;
int b;
short int c;
double d;
} END_PACK;
But yes, that's usually how it's done. Note that these are non-standard extensions.
C++11 has defined packing directives, but I don't know if they're supported by compilers yet.

unalignment warning when initializing SQL DBPROP structure

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;