northsideknight
northsideknight

Reputation: 1557

C struct memory storage order

I have a struct in C:

typedef struct {
    char member_a;
    char member_b;
    char member_c;
    char member_d;
} mystruct;

From what I understand, C structs store their members in memory contiguously. If I print out the struct's memory I can see that is the case, but it looks like the order of the members is reversed.

mystruct m;
m.member_a = 0xAA;
m.member_b = 0xBB;
m.member_c = 0xCC;
m.member_d = 0xDD;
printf("%X\n", m);

This outputs:

DDCCBBAA

Is this because the struct's member's values are stored in memory in reverse order? So the memory would look something like this, if m was stored at memory location 0x00 and each location was 1 byte in size:

memory location value
0x00 0xDD
0x01 0xCC
0x02 0xBB
0x03 0xAA

is this always the case with C? is this compiler specific? architecture specific? other?

Using gcc on Mac

Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 11.0.0 (clang-1100.0.33.17)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

Upvotes: 2

Views: 1325

Answers (2)

Peter - Reinstate Monica
Peter - Reinstate Monica

Reputation: 16120

The important thing to understand here is:

The textual representation of an integer says nothing about its internal representation. It is symbolic.

We accept that without a second thought for textual representations using base 10, or words: 65534 is as symbolic as sixtyfivethousandfivehundredthirtyfour.

But so is 0xfffe. It is a textual representation of an integral value that happens to be written using base 16 instead of base 10. By definition and definition only, borrowing from the decimal notation, digits to the left have higher values. This integral value, 65534, will always be written 0xfffe, no matter which bit pattern realizes it internally. This is one of the most important abstractions that the C programming language provides. It is the reason you always use the shift left operator for multiplication with 2, independent of the bit pattern and order the machine uses.

Any similarity to actual bit patterns, living or dead, is purely coincidental.

Upvotes: 1

klutt
klutt

Reputation: 31469

What you're doing is technically undefined behavior, so the compiler is allowed to do whatever it wants with it.

From what I understand, C structs store their members in memory contiguously.

Not really. But they are stored in the order they are declared.

If I print out the struct's memory I can see that is the case, but it looks like the order of the members is reversed.

That's because you're on a little endian machine. Try to add some more fields after the member_d field. You will likely get the same result. But as I said, it's undefined behavior, so you have no guarantees.

Here is a snippet that illustrates it.

https://onlinegdb.com/uXS2sk142

#include <stdio.h>
#include <stdint.h>
#include <memory.h>

int main(void) {
    int32_t x = 0xDDCCBBAA;
    char p[4];
    memcpy(p, &x, 4);
    
    for(int i=0; i<4; i++) {
        printf("%X", p[i]);
    }
}

It outputs this on a machine with little endian:

AABBCCDD

However, do note that a C compiler is free to add padding. So even if the order is guaranteed in memory, their position is not.

Related:

Detecting endianness programmatically in a C++ program

Structure padding and packing

Upvotes: 2

Related Questions