user1013944
user1013944

Reputation:

Structure and pointer

I'm having a problem getting the entry memory address to a member variable of a structure. I've tried in two ways, one of which didn't work properly. It would be very good if you guys give me some advice.

First, i defined a structure named BITMAP_HEADER.

struct BITMAP_HEADER
{
    WORD    bfType ;
    DWORD   bfSize ; 
    WORD    bfReserved1 ;
    WORD    bfReserved2 ;
    DWORD   bfOffBits ;
} ;

Second, i defined and initialized some variables. please look at the code below before you read next line. In case you ask me why i got a character pointer, i needed to access each bytes of integer bfSize.

struct BITMAP_HEADER    bitmap_header ;
char*                   pSize = (char*)&bitmap_header.bfSize;

Third, i got a memory address to the bfSize in two different ways and printed the values.

1. printf("%X\n", *pSize) ;
2. printf("%X\n", (unsigned char)*(((char*)&bitmap_header)+2)) ; 

(1) directly got a memory address to the bitmap_header.bfSize.

(2) got a memory address to the structure BITMAP_HEADER and shifted the pointer to the next by 2 bytes.

Finally, here is the result.

2D
F6

For your information, here is the hex data of the structure BITMAP_HEADER.

42 4D / F6 C6 2D 00 / 00 00 / 00 00 / 36 00 00 00

Why didn't the first method work? I thought the two methods were exactly same.

Upvotes: 1

Views: 251

Answers (2)

KBart
KBart

Reputation: 1598

As for the raw data which structure is known in advance, it usually better to read it to an array and use defined offsets to access required fields. This way you won't have to worry about compiler's behaviour (which might often be not as you expected). Your code would look like:

#define FIELD_TYPE  0
#define FIELD_SIZE  2
#define FIELD_RES1  6
#define FIELD_RES2  8
#define FIELD_OFF   10
#define SIZE_HEADER 14

static uint8_t header[SIZE_HEADER];

<...>
uint8_t * pheader = header;
DWORD offset_bits = (DWORD)*(pheader + FIELD_OFF);

P.S. to make this code portable, size of WORD and endianness must be considered, few #ifdef.. #else.. #endif should help with that.

P.P.S it would be even better use manual logical operations and shift operators instead of casting, but left it this way for the sake of brevity.

Upvotes: 0

sheu
sheu

Reputation: 5763

You're running into structure padding here. The compiler is inserting two bytes' worth of padding between the bfType and bfSize fields, to align bfSize to 4 bytes' size, since bfSize is a DWORD.

Generally speaking, you cannot rely on being able to calculate exact offsets within a structure, since the compiler might add padding between members. You can control this to some degree using compiler-specific bits; for example, on MSVC, the pack pragma, but I would not recommend this. Structure padding is there to specify member alignment restrictions, and some architectures will fault on unaligned accesses. (Others might fixup the alignment manually, but typically do this rather slowly.)

See also: http://en.wikipedia.org/wiki/Data_structure_alignment#Data_structure_padding

Upvotes: 2

Related Questions