On 6/16/2011 10:16 PM, Bhasker Penta wrote:
One way to test for endianess is to use a union:
void endianTest()
{
union // sizeof(int) == 4
{
int i;
char ch[4];
} U;
U.i=0x12345678; // writing to int member
if ( U.ch[0]==0x78 ) // reading from char member
puts("\nLittle endian");
else
puts("\nBig endian");
}
Please note that
One possible way to help to ensure that 'sizeof (int) == 4' and that you
have 8-bit bytes is to:
#define TT_ASSERT(message, test) \
typedef char (message)[(test) ? 1 : -1]
TT_ASSERT(INT_IS_NOT_4_BYTES, sizeof (int) == 4);
TT_ASSERT(NOT_8_BIT_BYTE, CHAR_BIT == 8);
Writing to one member of a union and reading from another member is
implementation defined(K& R).
As far as I know, if 'sizeof (int) == 4' as shown, you can certainly
read from each element of the 'U.ch' array. C doesn't guarantee that
'sizeof (int) == 4', of course.
Combined with the 'TT_ASSERT's above, you could have your union as:
union {
unsigned int i;
unsigned char ch[sizeof (unsigned int)];
} U;
(Note that the use of 'unsigned' attempts to avoid any potential sign
bit complications; the 'TT_ASSERT' might be better off matching, too.)
This example is used for testing
endianess @ c-faq.com. I know that gcc allows this. Is the above
snippet to test for endianess legal C or C++?
If you know that the implementation definitely uses an 8-bit byte, a
4-byte 'int', and that there are no padding bits and that '0x12345678'
is within the range of values for 'int', then I'd say yes for "legal C".
If you know that the implementation definitely uses an 8-bit byte, a
4-byte 'int', and that there are no padding bits and that '0x12345678'
is within the range of values for 'int', then I'd say yes for "legal C".
At least on my machine (Windows 7 64 bit) sizeof(int)==4,
sizeof(char)==1 and '0x12345678' is within 'int' limit. But the fact
is we are writing to int member and reading from (different) char
member. That doesn't go well with union rules.
I believe it's quite all right. 6.5.2.3p3 has:
"A postfix expression followed by the . operator and an identifier
designates a member of a structure or union object. The value is that of
the named member, and is an lvalue if the first expression is an lvalue.
If the first expression has qualified type, the result has the
so-qualified version of the type of the designated member."
Since you are using your 'ch' array, its element type is a character
type, and there are no trap representations for character types. The
last-stored value for the union has an object representation[6.2.6.1p4]
and that representation is then used for 'ch'.
Which union rules are you worried about, in particular?
If it is legal in C
language to reinterpret the content of any object as a char array (or
char pointer), then I believe above snippet is technically correct C
code(I may be wrong).
"char array": Yes. "char pointer": I think you mean if it's accessed
via a pointer to a character type. Yes, that's quite often the case.
One of the guarantees of the character types is that all objects can
have all of their bits manipulated/inspected via access through a
character type. This is useful for copying, for example. Scalar types
other than character types might have trap representations, if I recall
correctly.
Another nice thing about character types is that they have the weakest
alignment requirement; a pointer to a character type can be cast from
any other pointer-to-object-type because the alignment is fine[6.3.2.3p7]..
Eg.
int i=0x12345678; // sizeof(int) == 4
char *p=(char *)&i;
if(*p==0x78) // reinterpreting int ithrough a char
pointer
puts("Little Endian");
else
puts("Big Endian");
Absolutely as legitimate as your previous code.
(Using 'unsigned' variants are "nicer," in my opinion; no sign bit.)
On 6/16/2011 10:16 PM, Bhasker Penta wrote:
One way to test for endianess is to use a union:
void endianTest()
{
union // sizeof(int) == 4
{
int i;
char ch[4];
} U;
U.i=0x12345678; // writing to int member
if ( U.ch[0]==0x78 ) // reading from char member
puts("\nLittle endian");
else
puts("\nBig endian");
}
Please note that
One possible way to help to ensure that 'sizeof (int) == 4' and that you
have 8-bit bytes is to:
#define TT_ASSERT(message, test) \
typedef char (message)[(test) ? 1 : -1]
TT_ASSERT(INT_IS_NOT_4_BYTES, sizeof (int) == 4);
TT_ASSERT(NOT_8_BIT_BYTE, CHAR_BIT == 8);
Writing to one member of a union and reading from another member is
implementation defined(K& R).
As far as I know, if 'sizeof (int) == 4' as shown, you can certainly
read from each element of the 'U.ch' array. C doesn't guarantee that
'sizeof (int) == 4', of course.
Combined with the 'TT_ASSERT's above, you could have your union as:
union {
unsigned int i;
unsigned char ch[sizeof (unsigned int)];
} U;
(Note that the use of 'unsigned' attempts to avoid any potential sign
bit complications; the 'TT_ASSERT' might be better off matching, too.)
This example is used for testing
endianess @ c-faq.com. I know that gcc allows this. Is the above
snippet to test for endianess legal C or C++?
If you know that the implementation definitely uses an 8-bit byte, a
4-byte 'int', and that there are no padding bits and that '0x12345678'
is within the range of values for 'int', then I'd say yes for "legal C".
If you know that the implementation definitely uses an 8-bit byte, a
4-byte 'int', and that there are no padding bits and that '0x12345678'
is within the range of values for 'int', then I'd say yes for "legal C".
At least on my machine (Windows 7 64 bit) sizeof(int)==4,
sizeof(char)==1 and '0x12345678' is within 'int' limit. But the fact
is we are writing to int member and reading from (different) char
member. That doesn't go well with union rules.
I believe it's quite all right. 6.5.2.3p3 has:
"A postfix expression followed by the . operator and an identifier
designates a member of a structure or union object. The value is that of
the named member, and is an lvalue if the first expression is an lvalue.
If the first expression has qualified type, the result has the
so-qualified version of the type of the designated member."
Since you are using your 'ch' array, its element type is a character
type, and there are no trap representations for character types. The
last-stored value for the union has an object representation[6.2.6.1p4]
and that representation is then used for 'ch'.
Which union rules are you worried about, in particular?
If it is legal in C
language to reinterpret the content of any object as a char array (or
char pointer), then I believe above snippet is technically correct C
code(I may be wrong).
"char array": Yes. "char pointer": I think you mean if it's accessed
via a pointer to a character type. Yes, that's quite often the case.
One of the guarantees of the character types is that all objects can
have all of their bits manipulated/inspected via access through a
character type. This is useful for copying, for example. Scalar types
other than character types might have trap representations, if I recall
correctly.
Another nice thing about character types is that they have the weakest
alignment requirement; a pointer to a character type can be cast from
any other pointer-to-object-type because the alignment is fine[6.3.2.3p7]..
Eg.
int i=0x12345678; // sizeof(int) == 4
char *p=(char *)&i;
if(*p==0x78) // reinterpreting int ithrough a char
pointer
puts("Little Endian");
else
puts("Big Endian");
Absolutely as legitimate as your previous code.
(Using 'unsigned' variants are "nicer," in my opinion; no sign bit.)