Sign in to follow this  

struct alignment question

This topic is 1729 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hallo.

I understand that the size of a struct is not always the sum of it's innards, because there can be padding inbetween fields. What I am wondering is this:

Can I safely assume that two differently named structs types are the same (have the same size and same field offset) if they have the same arrangement of fields?

That is, can I assume that these two are the same:
struct a{
    int a;
    char b;
    long c;
    short d;
    double e;
};

struct a{
    int a;
    char b;
    long c;
    short d;
    double e;
};
even when they are defined in completely different places (different files, or different scope, or maybe anonymously defined)?

Share this post


Link to post
Share on other sites

Yes and no ;)

 

The names of the fields doesn't matter, just the type and ordering, so yes.

 

But you can change the packing with #pragma pack (or with a compile time switch) (on Visual C++ anyway, other compilers may have different options/pragmas), so no. The alignment can be different when the source or header file is compiled depending on what packing is active when the struct/class definition is parsed.

Edited by Paradigm Shifter

Share this post


Link to post
Share on other sites

Can I safely assume that two differently named structs types are the same (have the same size and same field offset) if they have the same arrangement of fields?  That is, can I assume that these two are the same, even when they are defined in completely different places (different files, or different scope, or maybe anonymously defined)?

Yes, their layout in memory should be the same.

 

For example, if you include the same structure declaration in various source files the objects must be interchangeable because they are the same layout.  If you have the object in foo.c and also in bar.c, you can pass the objects between functions in either file without problem.

 

 

 

As Paradigm Shifter pointed out, you can mess this up on your own by changing the alignment or padding options for the compiler, but that breaks lots of things.  Don't do that.

Share this post


Link to post
Share on other sites

The bigger question is WHY you would have 2 identical structs defined in multiple places which you wanted to treat as the same in multiple places. That's what header files are for.

Share this post


Link to post
Share on other sites
Ah, so as long as I don't use pragmas or __attribute__, it should be the same.

The reason I'm doing this is for convenience (and I'd say clarity of the code too).

I have this hash set type, and it can be used as a hash table if I just pass in a pair of values as a key. The thing is, I need to define a new struct for every pair (no std::pair<a, b> template in c). Rather than defining them at the top of the file with names that I might not remember, I think it is better to define it in the function where I actually need to use it.

Share this post


Link to post
Share on other sites

What does your implementation for your hash map look like? Does it use void* and size parameters or is it built with #define macros?

 

You might be better off defining an interface of function pointers instead and use that in the same way you would an abstract class in C++, (i.e. a list of function pointers like a vtbl) and passing one of those in to the create function of your hash map (which would be stored in the map and would call out to functions provided by concrete implementations for each type, like how qsort does for the comparison operator). Then your concrete implementations can cast from void* to the required type and back.

 

Or you could just use C++ ;)

Share this post


Link to post
Share on other sites
It looks like this:
When I create a new hash set, I pass in the element size, a comparison function pointer, and a hash function pointer. Adding a key involves using memcpy to copy "element size" number of bytes into the hash set's array. So yes, it's void* and element size.

Basically, I un-macro-ized the original macro implementation because it was getting messy to put things like "MAKE_HASHSET(int, INT_CMP, INTHASH)" everywhere.

The vtable you described there, what function pointer is needed? (besides comparison and hash) Edited by ultramailman

Share this post


Link to post
Share on other sites

That should do it (comparison and hash).

 

You can also store the element size and keysize when you create the hash map, then you can express the entire interface using void*, but you do lose the ability to use a literal key then (need to use a variable with an address).

 

hashmap* pMap = CreateHashSet(sizeof(int) /*keysize*/, sizeof(int) /* element size */, INT_CMP /* comparison func */. INTHASH /* hash func */);

 

int myKey = 0;

int myValue = 42;

pMap->InsertElement(&myKey, &myValue);

 

where the insert uses sizeof(int) stored as the keysize to copy the element, and InsertElement just uses void* parameters (size is known by the data associated with the map).

Edited by Paradigm Shifter

Share this post


Link to post
Share on other sites
That's pretty much how it is. Except it only takes keys as an argument.
/* inside a function*/
typedef struct int_pair{
    int key, val;
}int_pair;
struct hashset * hs = hashset_new(sizeof(int_pair), &int_cmp, &int_hash);
hashset_insert(hs, &(int_pair){0, 42});
It's true that it can't take literals, but it still behaves as if it is because it does make a copy of the thing.

Share this post


Link to post
Share on other sites

The bigger question is WHY you would have 2 identical structs defined in multiple places which you wanted to treat as the same in multiple places. That's what header files are for.

In fact, that's what header files DO.

Share this post


Link to post
Share on other sites

This topic is 1729 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this