3

I am working on an ARM project (SAMD21J18A) which reads a Bitmap file. Per the Bitmap specs, a bitmaps height will be a 4 byte long signed integer. In my struct, I am declaring the height as int32_t. Per the BMP specs, the height can be negative, but I also need to determine the actual height because the height's negative value can be expressed in "Two's complement" (correct me if I am wrong). To do this, I am reading the buffer like so (index 22-25 are the 4 bytes for the height)

bmp.height = *(int32_t*)&header_buff[22];

However, I receive the following compiler warning:

cast increases required alignment of target type [-Wcast-align]

I'm using the arm-none-eabi-gcc compiler.

Here is snippet of my code:

struct bitmap_t  {  
  int32_t width;
  int32_t height;       
  /* other properties left out for simplicity */
};

I am loading the first 54 bytes into a buffer to read the header:

struct bitmap_t bmp;
int8_t header_buff[54];
/* code to read the bmp here */
bmp.height = *(int32_t*)&header_buff[22];
rici
  • 234,347
  • 28
  • 237
  • 341
PhillyNJ
  • 3,859
  • 4
  • 38
  • 64
  • You'll also need to take endianness into account – pat Dec 02 '17 at 21:57
  • @user3386109 - Thanks you, but that poses another issue (perhaps needed in another post). If I do `bmp.height = (header_buff[25] << 24) | (header_buff[24] << 16) | (header_buff[23] << 8) | header_buff[22];` the value is represented in `Two's complaint notation`, which is not the correct value. – PhillyNJ Dec 02 '17 at 21:59
  • Make your comment an answer, which I believe answers by question - I will open another post, to address my `Two's complaint notation` issues. Thx – PhillyNJ Dec 02 '17 at 22:04
  • Is autocorrect changing "Two's complement" to "Two's complaint"? – pat Dec 02 '17 at 22:10

3 Answers3

2

If header_buff is aligned on a 4-byte boundary, then header_buff[22] is not on a 4-byte boundary. So you can't read the height like that. You need to read the bytes one at time and use shift and OR operations to recreate the height.

user3386109
  • 34,287
  • 7
  • 49
  • 68
2

You might just use memcpy to extract the value from header_buff while preserving its byte ordering:

memcpy(&bmp.height, &header_buff[22], sizeof(bmp.height));
Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
1

Using structures:

#pragma pack(push, 1)
struct S {
    int32_t d;
};
#pragma pack(pop)

int32_t get_doubleword_packet_with_struct(uint8_t *data) {
    S *s = (S *)data;
    return s->d;
}

Using memcpy:

int32_t get_d_packet_with_memcpy(uint8_t *data) {
    int32_t dst;
    memcpy(&dst, data, sizeof(dst));
    return dst;
}

My preferred way:

Define complete header into packed structure then retype bitmap into this structure, or put this structure into union with byte array and to this array copy header from bitmap.

#pragma pack(push, 1)
struct BitmapHeader {
    // ... here will be all fields from bitmap header
    int32_t width;
    int32_t height;
    // ....
};
#pragma pack(pop)

union Bmp {
    BitmapHeader header;
    uint8_t raw_data[sizeof(BitmapHeader)];
} bmp;

// copy data into bmp.raw_data array
// access fields from bmp.header.height ..

If you use cortex M3, M4, M7 or M33, it is possible to disable the warning, it will work. But on Cortex M0, M0+ and M23 it will not work, because unaligned access is not supported on these cores. But all my examples on M0 and M0+ will work, and compiler will use memcpy or just make 4 x read byte of the 32 bit number. This only if the struct is packed.

vlk
  • 2,581
  • 3
  • 31
  • 35