1

What is the best way to make sure that a C++ class conforms my expectations on how its data members are laid out?

I need to work with a class from 3rd party library. I know that this class is standard_layout and I know it contains certain public data members (to be specific, I am talking about a C struct here). However, I do not necessarily know in which order the members are laid out in the struct and I do not know if there are extra data members.

I need to be able to assert that the data members are laid out in a certain order and that there are no extra members because my objective is to put this struct in a union and use the special ruling from 9.2 about the common initial sequence of the union. Preferably, I would like this to be a static_assert of some kind, but a check in the build system using a small test program would be acceptable as well.

I was thinking of using the ofssetof macro to check the ordering of the members, but I am a bit at loss on how to make sure there are no additional members hidden in the padding.

EDIT

I suppose a way to rephrase the question is:

  1. can I detect the declaration order of a C struct (provided I know the names of its members),
  2. can I detect the presence of extra members in addition to the ones I know of?
bluescarni
  • 3,937
  • 1
  • 22
  • 33
  • Have you checked this one ? : http://stackoverflow.com/questions/4178175/what-are-aggregates-and-pods-and-how-why-are-they-special – Oragon Efreet Dec 12 '13 at 11:15
  • The declared order is just that, the declared order. Data members will not be reordered since it most likely will be code breaking at some point. Padding won't "hide" members. – StoryTeller - Unslander Monica Dec 12 '13 at 11:18
  • I am not sure I explained myself correctly, I know the original struct contains certain data members A,B,C but I do not know their declared order. I am trying to understand if I can detect the declaration order and the presence of an extra data member, e.g., declared between A and B. – bluescarni Dec 12 '13 at 11:21
  • Oragon Efreet: thanks for the link. I think I have a reasonable grasp of the differences between PODs, standard layout classes, etc. but I am going to go through the FAQ to see if there are any hints about the specifics of my question. – bluescarni Dec 12 '13 at 11:22
  • One alternative way you could test this would be to zeromemory the struct, set each member to a unique value (0xAAAAAAAA, etc) - you should then be able to copy the struct into a buffer (or cast it), compare each byte, and work out where each variable lives, and if there are any unset padding bytes. – benjymous Dec 12 '13 at 11:53
  • So you have nothing (names don't helps) and try to guess the header of a void* pointer to be able to include that in your own object. It could work seeking known value in the return object to find their position, then guessing the struct size, then trying to rewrite the struct header with object at your known position and fillers on the other places. Members can't change order from one call to the other is the only certain things. – ColdCat Dec 12 '13 at 12:24
  • It is an implementation detail so just look at the implementation. Write a little test program that writes the members of the struct. Look at the assembly that's generated by the compiler. – Hans Passant Dec 12 '13 at 13:53
  • Hold on. You know the names of the members, but you don't have the complete type declaration? How!? Why!? – StoryTeller - Unslander Monica Dec 12 '13 at 14:58
  • I have the complete declaration of the type, but the specification of the library mentions that in future more members might be added to the type. I was trying to understand if I could put a preemptive check for such future developments. – bluescarni Dec 12 '13 at 17:18
  • If they add member the struct size will change, if the struct size change the object can't be include in your object without recompilation. If you recompile with the last version they will never be any problems. It's already unlikely that member will change order from version to the next but as you will have to recompile to keep your union usable they will never be a problem even if everything change. – ColdCat Dec 12 '13 at 19:44
  • Also, you may write/use some external tool as clang-check with can provide an AST of the struct. – Jarod42 Dec 13 '13 at 11:24

1 Answers1

2

With offsetof, you may know the order (and the offset) of the member.

With sizeof, you may know the size the struct and each members.

but if the struct has padding, I don't see any way to detect is there is extra parameter.

struct S
{
    char c;
    // char padding[3];
    uint32_t u;
};

static_assert(offsetof(struct S, c) == 0, "expected c at 0");
static_assert(offsetof(struct S, u) == 4, "expected u at 4");
static_assert(offsetof(struct S, c) < offsetof(struct S, u), "expected c before u");
static_assert(sizeof(struct S) == 8, "expected size == 8");
static_assert(sizeof(struct S) - (sizeof(S::c) + sizeof(S::u)) == 3, "expected 3 bytes of padding");

So:

  1. yes you can know the order.

  2. yes if there is no padding.

Jarod42
  • 203,559
  • 14
  • 181
  • 302