Home > Software engineering >  Why final pointer is being aligned to size of int?
Why final pointer is being aligned to size of int?

Time:03-20

Here's the code under consideration:

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

char buffer[512];
int pos;
int posf;
int i;
struct timeval *tv;

int main(int argc, char **argv)
{
    pos = 0;
    for (i = 0; i < 512; i  ) buffer[i] = 0;
    for (i = 0; i < 4; i  )
    {
        printf("pos = %d\n", pos);
        *(int *)(buffer   pos   4) = 0x12345678;
        pos  = 9;
    }

    for (i = 0; i < 9 * 4; i  )
    {
        printf(" X", (int)(unsigned char)*(buffer   i));
        if ((i % 9) == 8) printf("\n");
    }
    printf("\n");

    // ---  

    pos = 0;
    for (i = 0; i < 512; i  ) buffer[i] = 0;
    *(int *)(buffer   4) = 0x12345678;
    *(int *)(buffer   9   4) = 0x12345678;
    *(int *)(buffer   18   4) = 0x12345678;
    *(int *)(buffer   27   4) = 0x12345678;

    for (i = 0; i < 9 * 4; i  )
    {
        printf(" X", (int)(unsigned char)*(buffer   i));
        if ((i % 9) == 8) printf("\n");
    }
    printf("\n");

    return 0;
}

And the output of code is

pos = 0
pos = 9
pos = 18
pos = 27
 00 00 00 00 78 56 34 12 00
 00 00 00 78 56 34 12 00 00
 00 00 78 56 34 12 00 00 00
 00 78 56 34 12 00 00 00 00

 00 00 00 00 78 56 34 12 00
 00 00 00 00 78 56 34 12 00
 00 00 00 00 78 56 34 12 00
 00 00 00 00 78 56 34 12 00

I can not get why

*(int *)(buffer   pos   4) = 0x12345678;

is being placed into the address aligned to size of int (4 bytes). I expect the following actions during the execution of this command:

  1. pointer to buffer, which is char*, increased by the value of pos (0, 9, 18, 27) and then increased by 4. The resulting pointer is char* pointing to char array index [pos 4];
  2. char* pointer in the brackets is being converted to the int*, causing resulting pointer addressing integer of 4 bytes size at base location (buffer pos 4) and integer array index [0];
  3. resulting int* location is being stored with bytes 78 56 34 12 in this order (little endian system).

Instead I see pointer in brackets being aligned to size of int (4 bytes), however direct addressing using constants (see second piece of code) works properly as expected.

  • target CPU is i.MX287 (ARM9);
  • target operating system is OpenWrt Linux [...] 3.18.29 #431 Fri Feb 11 15:57:31 2022 armv5tejl GNU/Linux;
  • compiled on Linux [...] 4.15.0-142-generic #146~16.04.1-Ubuntu SMP Tue Apr 13 09:27:15 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux, installed in Virtual machine;
  • GCC compiler version gcc (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
  • I compile as a part of whole system image compilation, flags are CFLAGS = -Os -Wall -Wmissing-declarations -g3.

Update: thanks to Andrew Henle, I now replace

*(int*)(buffer   pos   4) = 0x12345678;

with

        buffer[pos   4] = value & 0xff;
        buffer[pos   5] = (value >> 8) & 0xff;
        buffer[pos   6] = (value >> 16) & 0xff;
        buffer[pos   7] = (value >> 24) & 0xff;

and can't believe I must do it on 32-bit microprocessor system, whatever architecture it has, and that GCC is not able to properly slice int into bytes or partial int words and perform RMW for those parts.

CodePudding user response:

char* pointer in the brackets is being converted to the int*, causing resulting pointer addressing integer of 4 bytes size at base location (buffer pos 4) and integer array index [0]

This incurs undefined behavior (UB) when the alignments requirements of int * are not met.

Instead copy with memcpy(). A good compiler will emit valid optimized code.

// *(int*)(buffer   pos   4) = 0x12345678;
memcpy(buffer   pos   4, &(int){0x12345678}, sizeof (int));
  • Related