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.
Related
I know structure packing is a common thing in C++ programming (at least on low memory systems). But what about classes.
I know it works because I tried it
#include <iostream>
#pragma pack(push, 1)
class Test_Packed {
uint8_t t;
uint32_t test;
};
#pragma pack(pop)
class Test_Unpacked {
uint8_t t;
uint32_t test;
};
int main() {
std::cout<<sizeof(Test_Packed) << " / " << sizeof(Test_Unpacked)<<std::endl;
return 0;
}
Which correctly outputs "5 / 8".
Can I assume this to be the case on all conforming Compilers, or is this implementation defined?
I know that adding virtual members (and thus needing a vtable) will add additional data in the front. What can be other reasons for this to fail?
Can this cause any problems except for poor performance on some platforms?
The documentation for #pragma states:
Implementation defined behavior is controlled by #pragma directive.
So the effect, if any, of #pragma pack(push, 1) and #pragma pack(pop)
is completely "implementation defined."
Let's say we build 2 C++ DLLs as part of a huge in-house codebase: a Core.DLL and Another.DLL calling the Core.DLL. Each DLL gets built with the same version of Visual Studio but with very different project settings, including e.g. C/C++->Code Generation->Struct Member Alignment.
Now let's say we pass a reference to CoreData when calling Core.DLL from Another.DLL, but the CoreData is not dllexported, it is defined by each DLL independently.
What makes it dangerous to use a non-dllexported class CoreData in such context? Which project settings are particularly important to keep identical between the DLLs, if we had to (at gunpoint) employ the generally unsafe practice ?
I know that we should be dll-interfacing only with POD types and abstract interfaces (COM-like), the purpose of the question is to learn what really goes on behind the curtains, if one doesn't follow those rules. I will follow these rules, just have to learn how to figure out what to fix first in a large codebase.
Below is my pseudo-code to illustrate the question.
In-depth explanations as well as links to articles or books are very welcome. I've seen a few similar questions on SO but none seemed to be deep enough.
EDIT: wrapped API header in #pragma pack to counter the different Struct Member Alignment project settings. Is it safe now, or are there any other project settings to keep an eye on?
Cheers!
// CoreDllApi.h
#pragma once
#ifdef COREDLL_EXPORTS
#define COREDLL_API __declspec(dllexport)
#else
#define COREDLL_API __declspec(dllimport)
#endif
#pragma pack(push,8)
class CoreData
{
public:
CoreData():a(0),b(0),c(.0){}
CoreData(int a, int b, double d):a(a),b(b),c(c){}
virtual bool IsValid() {return true;}
int a;
int b;
double c;
};
#pragma pack(pop)
class COREDLL_API CoreRetriever
{
static void get(int id, CoreData &out);
};
// AnotherDll.cpp:
#include "CoreDllApi.h"
#include <iostream>
static void ProcessData(int id)
{
CoreData data;
CoreRetriever::get(id, data); // danger?
std::cout << data.a << ";" << data.b << ";" << data.c << std::endl;
}
I have a class that is exported and it uses a header only structure as a member variable.
#include "SomeStruct.h"
class API_CLASS SomeClass
{
public:
// ...
private:
#pragma warning( push )
#pragma warning( disable: 4251 )
SomeStruct _active;
#pragma warning( pop )
};
I get warning 4251 as the structure is not exported. The structure is part of an external code and not a part of current scope.
I would like to make this code a bit more readable as this is a header I will distribute.
Ideally, I want the class to read
#include "SomeStruct.h"
class API_CLASS SomeClass
{
public:
// ...
private:
DISABLE_WARNING_BEGIN(4251)
SomeStruct _active;
DISABLE_WARNING_END
};
It may be more work to disable multiple warnings but if that can be done, then great but not necessary. The macro should result in code only for WIN32 environment. I have tried to write the macro but to include a '#' is beyond me.
I can live with this. This is better than what I have now.
#include "SomeStruct.h"
class API_CLASS SomeClass
{
public:
// ...
private:
#pragma warning(suppress: 4251)
SomeStruct _active;
};
Thanks to Heinirichj
To add #pragma into a MACRO, you may use:
__pragma with MSVC
_Pragma with gcc
See Pragma in define macro for more detail.
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.
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.