Jump to content

  • Log In with Google      Sign In   
  • Create Account

struct alignment question


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
9 replies to this topic

#1 ultramailman   Prime Members   -  Reputation: 1585

Like
0Likes
Like

Posted 23 April 2013 - 12:34 PM

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)?

Sponsor:

#2 Paradigm Shifter   Crossbones+   -  Reputation: 5434

Like
1Likes
Like

Posted 23 April 2013 - 12:46 PM

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, 23 April 2013 - 12:46 PM.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

#3 frob   Moderators   -  Reputation: 22718

Like
0Likes
Like

Posted 23 April 2013 - 01:14 PM

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.


Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I write about assorted stuff.


#4 Paradigm Shifter   Crossbones+   -  Reputation: 5434

Like
0Likes
Like

Posted 23 April 2013 - 01:17 PM

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.


"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

#5 ultramailman   Prime Members   -  Reputation: 1585

Like
0Likes
Like

Posted 23 April 2013 - 01:57 PM

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.

#6 Paradigm Shifter   Crossbones+   -  Reputation: 5434

Like
0Likes
Like

Posted 23 April 2013 - 02:19 PM

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++ ;)


"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

#7 ultramailman   Prime Members   -  Reputation: 1585

Like
0Likes
Like

Posted 23 April 2013 - 02:56 PM

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, 23 April 2013 - 02:57 PM.


#8 Paradigm Shifter   Crossbones+   -  Reputation: 5434

Like
0Likes
Like

Posted 23 April 2013 - 03:11 PM

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, 23 April 2013 - 03:12 PM.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

#9 ultramailman   Prime Members   -  Reputation: 1585

Like
0Likes
Like

Posted 23 April 2013 - 03:29 PM

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.

#10 Bregma   Crossbones+   -  Reputation: 5435

Like
0Likes
Like

Posted 23 April 2013 - 03:30 PM

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.


Stephen M. Webb
Professional Free Software Developer




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS