How is a struct organized in memory?

3

How does access to struct work? Can I put the members in the order I want? How does the compiler know which part of memory it should access? How would this look?

struct {
   char ch1;
   short s;
   char ch2;
   long long ll;
   int i;
};
    
asked by anonymous 10.02.2017 / 13:37

1 answer

3

An array is a sequence of elements of a certain type, right? The array is a memory location where it will have the first element (0), and then another similar element, and so on.

If the data type has 1 byte and the array has 10 elements, it will occupy 10 bytes, one after the other, as if it were one thing.

If the type has 4 bytes, it will have 40 bytes.

To navigate between elements, when accessing var[5] , where it stores int s, is actually accessing *(var + 5 * sizeof(int)) , then probably (depends on the platform) if var points to memory address 100 ), this access will occur at position 120 of the memory (100 + 5 * 4).

Well, a struct is a sequence of members of varying types. These members are arranged one behind the other as in the array , but the size of each member will vary according to its type. Then the access of var.ll is accessed by the address of the variable, plus the size of all previous members. In this example the question would be var + sizeof(ch1) + sizeof(s) + sizeof(ch2) . You actually have to consider alignment as well. Then the most correct is to use the offsetof operator that gives the correct offset of each member.

To facilitate we will align better and see how it is:

#include <stdio.h>
#include <stddef.h>

typedef struct {
    long long ll;
     int i;
     short s;
     char ch1;
     char ch2;
} Tipo; 

int main(void) {
    Tipo var = { .ll = 1000000000000, .i = 1000, .s = 10, .ch1 = 'a', .ch2 = 's' };
    printf("%lld\n", var.ll);
    printf("%i\n", var.i);
    printf("%d\n", var.s);
    printf("%c\n", var.ch1);
    printf("%c\n", var.ch2);
    printf("%lld\n", *((long long*)(((char*)&var) + offsetof(Tipo, ll))));
    printf("%i\n", *((int*)(((char*)&var) + offsetof(Tipo, i))));
    printf("%d\n", *((short*)(((char*)&var) + offsetof(Tipo, s))));
    printf("%c\n", *((char*)(((char*)&var) + offsetof(Tipo, ch1))));
    printf("%c\n", *((char*)(((char*)&var) + offsetof(Tipo, ch2))));
}

See running on ideone . And at Coding Ground . Also put it on GitHub for future reference .

The second sequence of prints produces the same result, but doing arithmetic in the hand, which is much more complicated. Let the compiler do it for us.

On the hand is doing:

  • get address of variable var
  • cast to turn everything into byte ( char * ) and be able to manipulate the bytes freely
  • find member offset and sum with variable address
  • cast for the member type
  • get the contents of the found address

The beauty of C is precisely to treat everything in the most concrete and simple way possible. Understanding is more complicated than effective implementation. A structure is just a map for memory addresses.

So in this example% w / o the access would be:

typedef struct {
    long long ll; // na posição 0
     int i;       // na posição 8
     short s;     // na posição 12
     char ch1;    // na posição 14
     char ch2;    // na posição 15
} Tipo;
    
10.02.2017 / 13:37