0

I know that you can effectively perform the following code to convert a struct into a byte array,

struct Dummy
{
  int a;
  int b; 
};

Dummy data;
char* buffer = reinterpret_cast<char*>(&data);

Then we can access each of the 8 bytes, one by one, using the char array pointer.

My question is can you do the same with a class in a similar manner?

class Dummy
{
private:
  int a;
  int b; 
};

Dummy data;
char* buffer = reinterpret_cast<char*>(&data);
Adriano
  • 80
  • 11
  • 5
    `class` and `struct` only differ in default access modifier. – Osyotr Dec 13 '21 at 21:32
  • So under the covers it's exactly the same? Even with the ordering? – Adriano Dec 13 '21 at 21:33
  • This is currently a gray area of the standard. `buffer` is a valid pointer but what you can do with it depends on your interpretation of the standard. An optimistic interpretation (and I believe the intended one) will allow both of these cases to access the entire representation. But `Dummy` is trivially copyable in both cases, for non-trivial types the actual representation you can access won't be very meaningful. You couldn't write to it safely, and there isn't much you could do with the information you get you would get read from reading from it. – François Andrieux Dec 13 '21 at 21:33
  • @FrançoisAndrieux: Is the ordering of `a` and `b` guaranteed by the standard when they're `private`? I'd hope the standard allows reordering for `private` members for optimization purposes, but I'm not sure. If reordering is allowed, there'd be no guarantee the bytes read even come from a specific member, even if the size and padding rules are all known. – ShadowRanger Dec 13 '21 at 21:42
  • Yes, any object of any type - you are allowed to examine the bytes. – Aykhan Hagverdili Dec 13 '21 at 21:42
  • https://stackoverflow.com/questions/65201486/is-the-compiler-allowed-to-optimise-out-private-data-members – Sergey Kolesnik Dec 13 '21 at 21:46
  • @ShadowRanger if I recall correctly, sections separated with access specifiers are allowed to be reordered as a whole. But members in the same section may not be reordered. – Aykhan Hagverdili Dec 13 '21 at 21:46
  • @FrançoisAndrieux There is lots of code that can depend on correct order in a struct. For example a POD struct that represents a file header. – Offtkp Dec 13 '21 at 21:53
  • @Offtkp I guess I had a narrow view of the problem. I was just thinking of accessing individual members via the `buffer` pointer. – François Andrieux Dec 13 '21 at 21:55
  • Padding is also important in this context. By accessing the bytes one by one, you may get some garbage too since some of the bytes might be there only for padding/optimization purposes. – digito_evo Dec 13 '21 at 22:31

1 Answers1

1

The only difference between class and struct is the default access modifier which for struct is public and for class is private. In c++ standard you can actually read about classes while in examples you have structs: https://eel.is/c++draft/class.prop

Technically your code is correct, for example it does not cause undefined behaviour. Strict aliasing rules are not violated - you can use char type to access stored value of your object:

http://www.eel.is/c++draft/expr.prop#basic.lval-11.3

The question is what you want to do with this pointer? For example, if you want to implement serialization then you need to make sure your class is_trivially_copyable:

https://en.cppreference.com/w/cpp/types/is_trivially_copyable

Objects of trivially-copyable types that are not potentially-overlapping subobjects are the only C++ objects that may be safely copied with std::memcpy or serialized to/from binary files with std::ofstream::write()/std::ifstream::read().

Your class passes this test:

static_assert(std::is_trivially_copyable<Dummy>::value, "Cannot be copied with memcpy");

You need to also be aware of the various problems such object access can cause: alignments, field padding, packing etc. Under visual studio I used to use #pragma pack(1) to make sure all the fields in the class are byte packed. But this removes many optimizations and should not be used unless there is no other solution.

marcinj
  • 48,511
  • 9
  • 79
  • 100