Why CodeWarrior couldn't handle unions???

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Why CodeWarrior couldn't handle unions???

4,731 Views
fiskom
Contributor I
Hello,
I use C as language:

So i have declared unions, take a look:
****
union Byte{
char c;
unsigned char uc;
};
union DoubleByte{
union Byte by[2];
WORD w;
UWORD uw;
};
****
But if i call sizeof:
union Byte = 2
union DoubleByte = 4

Why did the codewarrior compiler do this? (Double size???)
And why it places the startaddress of ,e.g., by[1] in union DoubleByte at a place 2 bytes away from the startaddress of by[0]?
I have tested other compilers and they did the work! I mean, they don't put a 2-byte distance between two entries of an 1-byte-Array.

Can anyone tell me, if this is an option to configure in the IDE or is this bug something, the other compilers should do also, if they would do correct C.

Thanks
Labels (1)
0 Kudos
16 Replies

1,026 Views
Nouchi
Senior Contributor II
Hi,

Union size, is the size of the biggest object belong to the union, so it depends on your processor target, compiler, WORD and UWORD typedef definition.
Maybe WORD or UWORD are 4 bytes wide?

Emmanuel
0 Kudos

1,026 Views
fiskom
Contributor I
Thats right, but these are my 'typedefs':

typedef short int WORD;
typedef unsigned short int UWORD;

already checked:
sizeof(WORD) = 2
sizeof(UWORD) = 2

And that also wouldn't explain, why the 'union Byte' has a size of 2 Byte!!!
I tested this:
union Byte{unsigned char uc;};
union Test{unsigned char uc[2];};

The sizeof()-calls of these two Unions return '2' and that isn't right!!!
0 Kudos

1,026 Views
Nouchi
Senior Contributor II
You don't tell us which processor you used, maybe it has an even address constraint alignment, so the compiler add a pad byte to force alignment.
you should have a look to compiler message, it warn you when it add pad byte with this kind of message :
Warning : 1 pad byte(s) inserted after data member 'status'
Dtypes.h line 65 }msgCAN;


Emmanuel
0 Kudos

1,026 Views
fiskom
Contributor I
I use the ColdFire PCF5213CAF (32-bit) its part of the M5213EVB.
And i have checked the option "Pad Bytes Added*" under "C/C++ Warnings", but I don't gain a warning.

But doesn't matter anymore, i have changed my code to:
****
union DoubleByte{
/*work-around code warrior problem with 1-byte-unions*/
unsigned char by[2];
char c[2];
unsigned char uc[2];
WORD w;
UWORD uw;
};
****
sizeof(union DoubleByte) = 2

Although, Thank you

Message Edited by fiskom on 2007-02-0709:50 AM

0 Kudos

1,026 Views
CompilerGuru
NXP Employee
NXP Employee
Looks like the warning is only issued for structs, not for unions.
The "ColdFire Processor" "Struct Alignment" does actually define the behavior for unions too. As the pref panel does not contain the packed entry, a pragma can be used:

#pragma push
#pragma options align=packed
typedef union {
char c;
} Union1Byte;
#pragma options align=mac68k
typedef union {
char c;
} Union2Byte;
#pragma pop

Daniel
0 Kudos

1,026 Views
fiskom
Contributor I
Thank you, for that #pragma-workarround. The problem is cleared.
0 Kudos

1,026 Views
Lundin
Senior Contributor IV
It is a compiler bug then.

If the compiler says that sizeof(type_x) == 2 and sizeof(type_y) == 2, then there can never be a reason for the compiler to make the union of the two types anything but 2. Padding shouldn't be applied in this situation. If it is, then it is a rather serious bug. Because the cpu can obviously handle addresses of variables that are less than 4 bytes or the compiler would have allocated both the individual variables and the union as 4 bytes.
0 Kudos

1,026 Views
CompilerGuru
NXP Employee
NXP Employee
Lundin, no, it is not a compiler bug.
The compiler does not behave as one would expect, but it complies to the standard it is supposed to.
I don't know where this tail padding of 1 byte structs to always a multiple of 2 originates, could have some historical background, but in the end it does not matter.
It is as it is, the current state is correct (using ANSI-C as measurement), and changing such things breaks the compatibility (of applications using non ANSI-C defined parts).

I would agree to call it an oddity, but I clearly object to call it a "rather serious bug".

Daniel
0 Kudos

1,026 Views
Lundin
Senior Contributor IV
Call it a bug or oddity or whatever you like, it is an unexpected behavior of the program caused by the compiler.

What if the variables used are referring to hardware registers?

The programmer wish to use the two 8-bit registers "A" and "B" either as individual registers or as an array of registers. So he writes an union:

typedef union
{
struct
{
char A;
char B
};

char array[2];

}Something;

Something s;

for( loop from 0 to sizeof(Something) )
s[i]=value;

And what happens? The code looped 4 times and wrote to the two hardware registers located after A and B and caused a nuclear meltdown. The programmer has done nothing wrong: he knows that the cpu he is using can address variables at even 16-bit address. The compiler port to the specific processor is faulty.
0 Kudos

1,026 Views
sjmelnikoff
Contributor III

Lundin wrote:
Call it a bug or oddity or whatever you like, it is an unexpected behavior of the program caused by the compiler.
...
And what happens? The code looped 4 times and wrote to the two hardware registers located after A and B and caused a nuclear meltdown. The programmer has done nothing wrong: he knows that the cpu he is using can address variables at even 16-bit address. The compiler port to the specific processor is faulty.

The problem is not with the compiler; it is due to the flexibility (or perhaps, ambiguity) in the C standard, and demonstrates why you have to be very careful with unions. As well as padding and alignment, endidanness (i.e. big-endian or little-endian) and bit order vary with different compilers.
 
Safe options for using unions are:
  • Use them only for sharing memory space, where the overlapping areas are used for different things at different times. In other words, don't use unions to access the same data in two different ways (as done in the above example).
  • If you use them in the manner described above, read the compiler manual to make sure you understand how they will be implemented.

Steve.

0 Kudos

1,026 Views
bigmac
Specialist III
Hello Steve,
 


sjmelnikoff wrote:
 
Safe options for using unions are:
  • Use them only for sharing memory space, where the overlapping areas are used for different things at different times. In other words, don't use unions to access the same data in two different ways (as done in the above example).
  • If you use them in the manner described above, read the compiler manual to make sure you understand how they will be implemented.

Steve.


If using a union cannot be safely used to "access the same data in two different ways", I am wondering what are the safe alternatives?
 
Let's say we need to send the representation of a multiple byte value to a peripheral that handles only one byte at a time, for example, a SPI module.  A union does seem to be a convenient way to handle this situation - say relating a double word to a 4-byte array, etc.  I agree that, for some applications, the endianess would need to be known, and in others it would not, e.g. writing and reading a serial EEPROM device.  However, I would expect that the individual array bytes combined would reflect the double word value.
 
If this cannot be guaranteed, what are the alternatives?
 
Regards,
Mac
 
0 Kudos

1,026 Views
CompilerGuru
NXP Employee
NXP Employee
First note that Lundin's example does not actually expose the specific behavior of the compiler this thread was about.
Instead the code would work as expected and the nuclear meltdown would not happen, uff.
This thread was about the alignment of unions, and this alignment only happens for otherwise odd sized unions. The only way to actually declare such a union is one which does only contain 1 byte sized types (say char's).

Anyway, the standard does actually guarantee that the various union members do start at the same address, but it does not guarantee that a struct with 2 members has the same memory layout as an array with 2 fields. The only portable thing you can do with a union is to read the same members you wrote into.

In the end, as we talk here about the use of those constructs to access HW registers, whoever writes the header files will have to check that the structures map properly to the memory layout.
Using unions is perfectly fine, but you have to check how the compiler maps them to the memory layout. You can do this check by either by experiment or by reading the compiler documentation.
Not sure how good the CF compiler documentation is in this respect, at least it does document the #pragma's which can be used to switch of the alignment, and then even the 1 byte union case gets allocated as expected.

Daniel
0 Kudos

1,026 Views
Lundin
Senior Contributor IV
Yes, the C standard is vauge and allows all kind of crazy stuff. ANSI C forces sizeof(unionType) to include padding bytes, so if there are padding bytes in the union, the compiler manufacturer has no other choise than displaying them. I guess my point is:

- When the compiler is ported to a specific target, why add wee padding bytes if the cpu won't have an alignment problem? Yes, on most cpu:s misaligned bytes will take a few ticks longer to access, but if the programmer is concered about that, he can allocate the variables manually at even locations in his memory map. He is writing in C after all, so it can't be a big issue since most of the variables will end up on the stack anyway.
0 Kudos

1,026 Views
sjmelnikoff
Contributor III

Lundin wrote:
Yes, on most cpu:s misaligned bytes will take a few ticks longer to access, but if the programmer is concered about that, he can allocate the variables manually at even locations in his memory map.

On the contrary; the programmer should not have to worry about things like that - unless it becomes relevant, as the above examples demonstrate. 

Lundin wrote:

He is writing in C after all, so it can't be a big issue since most of the variables will end up on the stack anyway.

If you're using static, file-scope or global variables, that's not true.
 
Steve.
0 Kudos

1,026 Views
Lundin
Senior Contributor IV
Therefore "most variables". But if the programmer is in dire need of speed for his globals/statics, he can allocate them at aligned addresses, which was my point. If he doesn't allocate them manually, then they will be placed in some memory chunk together with other globals/statics and he can no longer assume that they are placed at aligned addresses.
0 Kudos

1,026 Views
sjmelnikoff
Contributor III

bigmac wrote:
 
If using a union cannot be safely used to "access the same data in two different ways", I am wondering what are the safe alternatives?
...
If this cannot be guaranteed, what are the alternatives?

I think the issue here is the assumption that unions are implemented in the same way on all compilers, and in an intuitive manner. As the original poster discovered, this is not the case!
 
A union can be used safely, provided you do your homework - namely, check the compiler manual, and try out code to see what is actually produced, e.g. using sizeof, as above; looking at the map file to see how much space is actually allocated; perhaps looking at the assembly code.
 
In the specific case of using a union to provide byte and bit access, such as for a port or register, using masks is one unambiguous alternative.
 
Steve.
0 Kudos