View previous topic :: View next topic |
Author |
Message |
Benjamin
Joined: 11 Jan 2006 Posts: 21 Location: Quebec (Canada)
|
Problem with structure size |
Posted: Fri Jan 28, 2011 2:49 pm |
|
|
Hello,
I've been having problems with structures lately, and found that the size of my structures are not giving what I expected. To simplify my problem, I've written the following program:
Code: |
void main (void)
{
unsigned int16 size;
struct _diskinfo
{
char jmpBoot[3];
char OEMName[8];
unsigned int16 BytsPerSec;
char SecPerClus;
unsigned int16 RsvdSecCnt;
char NumFATs;
unsigned int16 RootEntCnt;
unsigned int16 TotSec16;
char Media;
unsigned int16 FATSz16;
unsigned int16 SecPerTrk;
unsigned int16 NumHeads;
unsigned int32 HiddSec;
unsigned int32 TotSec32;
} fDiskInfo;
size = sizeof(fDiskInfo);
fprintf(PC,"Size = %u\r\n",size);
while(1);
}
|
The size printed is 40.
This is confirmed from the list file:
Code: |
.................... size = sizeof(fDiskInfo);
00BB4: MOV #28,W4
00BB6: MOV W4,2FE6
|
And from the .sym:
Code: |
2FE6-2FE7 main.size
2FE8-300F main.fDiskInfo
|
But from my calculation it should be the following:
7*2(int16) + 2*4(int32) + 14*1(char) = 36
What is it I'm not getting?
I'm using a 33FJ256GP710 and compile with the latest version 4.118.
I'm new with 16 bit parts, so there may be something I'm not getting.
Thanks in advance,
Ben |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jan 28, 2011 3:05 pm |
|
|
It's possible that the compiler is padding the elements to 'int16' size.
It may also pad the whole structure out to a mulitple of 'int32'.
It's common for compilers (such as MSVC++) to do this. I don't see
a "pragma pack" option in the PCD manual which would let you control
the packing. Or it could be a bug. You could investigate if it's a packing
issue with the offsetof() function to display the offsets of the individual
structure elements. |
|
|
Benjamin
Joined: 11 Jan 2006 Posts: 21 Location: Quebec (Canada)
|
|
Posted: Fri Jan 28, 2011 3:27 pm |
|
|
Thanks! You're right. The compiler does "pad" the elements to 'int16' size.
offsetof(fDiskInfo,BytsPerSec); returns 12. So the compiler adds a byte after OEMName and probably adds one after each 'char' after this which explains the 4 extra bytes.
I understand why the compiler would do this, but this is a little problematic since the structures must respect the byte pattern of some specs which I cannot change (as in FAT32 and others). I'm porting a program from an 8bit PIC to 16 bits and I have a dozen structures like this one.
There must be a way of deactivating this? I haven't checked the doc for this yet and will be doing that on Monday. But if anyone has an answer till than it would be appreciated.
Thanks. |
|
|
Benjamin
Joined: 11 Jan 2006 Posts: 21 Location: Quebec (Canada)
|
|
Posted: Wed Feb 09, 2011 10:07 am |
|
|
Here's an update in case someone else runs into the same problem.
The CCS manual does mention that the compiler will align 16 bit fields in a structure to even bytes.
And when asked if it is possible to avoid this, here's the response from CCS:
Quote: |
Yes, you can use the GCC attribute for this.
It looks like this:
struct __attribute__((packed))
{
uint8_t a_0;
uint16_t a_12;
uint8_t a_3;
uint8_t a_4;
uint16_t a_56;
uint8_t a_7;
uint16_t a_89;
uint8_t a_a;
};
I would refer to the GCC manual for more info.
It is relatively new to the compiler, that is why it's not documented yet.
You also have to be careful using it, because addressing a word pointer if it's not word aligned will cause address failure on a 16bit PIC. This should only happen if you manually created a pointer to an individual entry in the structure, which according to many C purists is bad code design.
|
I haven't tested it yet, but this should fix my problems.
Benjamin |
|
|
|