Anni_housie
Anni_housie

Reputation: 489

Confuse about data address alignment

I have a question about the answer provided by

@dan04. What is aligned memory allocation?

In particular, if I have something like this:

int main(){
      int num;  // 4byte
      char s;   // 1byte
      int *ptr;


}

If I have a 32 bit machine, do you think it would still be padding at the data by default?

In the previous question, it was asked about struct, and I am asking about variables declared in main.

update:

a = 2 bytes 
b = 4 bytes
c = 1 byte
d = 1 byte



 0 1 2 3 4 5 6 7
|a|a|b|b|b|b|c|d|  bytes
|       |       |  words

Upvotes: 3

Views: 134

Answers (2)

4386427
4386427

Reputation: 44246

There are no rules for this. It depends on the implementation you are using. Further it may change depending on compiler options. The best you can do is to print the address of each variable. Then you can see how the memory layout is.

Something like this:

int main(void)
{
  int num; 
  char s;   
  int *ptr;

  printf("num: %p - size %zu\n", (void*)&num, sizeof num);
  printf("s  : %p - size %zu\n", (void*)&s, sizeof s);
  printf("ptr: %p - size %zu\n", (void*)&ptr, sizeof ptr);

  return 0;
}

Possible output:

num: 0x7ffee97fce84 - size 4
s  : 0x7ffee97fce83 - size 1
ptr: 0x7ffee97fce88 - size 8

Also notice that in case you don't take the address (&) of a variable, the compiler may optimize your code so that the variable is never put into memory at all.

In general the alignment is typically made to get the best performance out of the HW platform used. That typically imply that variables are aligned to their size or at least 4 byte aligned for variables with size greater than 4.

Update:

OP gives a specific layout example in the update and asks if that layout can/will ever happen.

Again the answer is: It is implementation dependent

So in principle it could happen on some specific system. That said I doubt that it will happen on any mainstream system.

There is another code example compiled with gcc -O3

int main(void)
{
  short s1;
  int i1;
  char c1;
  int i2;
  char c2;


  printf("s1: %p - size %zu\n", (void*)&s1, sizeof s1);
  printf("i1: %p - size %zu\n", (void*)&i1, sizeof i1);
  printf("c1: %p - size %zu\n", (void*)&c1, sizeof c1);
  printf("i2: %p - size %zu\n", (void*)&i2, sizeof i2);
  printf("c2: %p - size %zu\n", (void*)&c2, sizeof c2);

  return 0;
}

Output from my system:

s1: 0x7ffd222fc146 - size 2   <-- 2 byte aligned
i1: 0x7ffd222fc148 - size 4   <-- 4 byte aligned
c1: 0x7ffd222fc144 - size 1
i2: 0x7ffd222fc14c - size 4   <-- 4 byte aligned
c2: 0x7ffd222fc145 - size 1

Notice how the location in memory differs from the order variables was defined in the code. That ensures a good alignment.

Sorting by address:

c1: 0x7ffd222fc144 - size 1
c2: 0x7ffd222fc145 - size 1
s1: 0x7ffd222fc146 - size 2   <-- 2 byte aligned
i1: 0x7ffd222fc148 - size 4   <-- 4 byte aligned
i2: 0x7ffd222fc14c - size 4   <-- 4 byte aligned

So again to answer the update-question:

On most systems I doubt you'll see a 4 byte variable being placed at address xxx2, xxx6 or xxxa, xxxe. But still, systems may exist where that could happen.

Upvotes: 5

Eliran Abdoo
Eliran Abdoo

Reputation: 611

It's quite hard to exactly predict, but there's certainly some padding going on. Take these two codes for example (I run them on Coliru, 64bit machine)

    #include<iostream>
#include <vector>
using namespace std;

//#pragma pack(push,1)
int main(){    
      int num1(5);  // 4byte
      int num2(3);   // 4byte
      char c1[2];
      c1[0]='a';
      c1[1]='a';
      cout << &num1 << " " << &num2 << " "  << endl;     
      cout << sizeof(c1) << " " << &c1 << endl;

}
//#pragma pack(pop)




    #include<iostream>
#include <vector>
using namespace std;

//#pragma pack(push,1)
int main(){    
      int num1(5);  // 4byte
      int num2(3);   // 4byte
      char c1[1];
      c1[0]='a';
      cout << &num1 << " " << &num2 << " "  << endl;     
      cout << sizeof(c1) << " " << &c1 << endl;

}
//#pragma pack(pop)

The first program outputs:

0x7fff3e1f9de8 0x7fff3e1f9dec 
2 0x7fff3e1f9de0

While the second program outputs:

0x7fffdca72538 0x7fffdca7253c 
1 0x7fffdca72537

You can definitely notice that there's a padding being made in the first program, looking at the addresses we can see that: First program: CHAR | CHAR | 6-BYTE PADDING | INT | INT Second program: CHAR | INT | INT

So for the basic question, yes it is probably padding by default. I also tried to use pragma pack to avoid padding, and in contrast to the struct case, I didn't manage to make it avoid padding, since the outputs were exactly the same.

Upvotes: 1

Related Questions