Re: How should I test endianness in C or C++?

  • From: Dave <davidct1209@xxxxxxxxx>
  • To: programmingblind@xxxxxxxxxxxxx
  • Date: Tue, 20 Jul 2010 08:43:51 -0700

Checkout the call to calloc.  How large is your struct in bytes?

Hth,
Dave

On 7/20/10, Delaunay Christophe <christophe.delaunay@xxxxxxxxxxxxxxx> wrote:
> Hi Joseph,
>
> Many thanks for your suggestion. Although I don't like such hardcoded
> assumptions, I implemented the workaround you proposed and the app seems
> to do what I want either under windows when compiled with Visual C++
> 2005 pro, or under linux when compiled with GCC 4.3.3.
>
> Here is the final code:
>
> ------ BEGINNING OF CODE ------
> /**
>  *
>  * This small programs tests and explains endianness.
>  *
>  */
>
> /* --- The needed header files --- */
> #include <stdio.h> /* for input and output */
> #include <stdlib.h> /* calloc() */
> #include <malloc.h> /* calloc() */
>
> /* --- Given definition --- */
> #ifdef WIN32 /* windows-like OS assumed */
> #define ATTRIBUTE
> #define uint8_t       unsigned char
> #define       __LITTLE_ENDIAN 1234
> #define       __BIG_ENDIAN    4321
> #define       __PDP_ENDIAN    3412
> #define __BYTE_ORDER __LITTLE_ENDIAN
> #else /* linux-like OS assumed */
> #include <inttypes.h> /* special integer types */
> #include <endian.h> /* defines appropriate macros to test endianness. */
> #define ATTRIBUTE     __attribute__((packed))
> #endif /* windows or linux */
>
> /* --- The byte divided into 8 bit fields --- */
> typedef struct _bitfields {
> #if __BYTE_ORDER == __LITTLE_ENDIAN
>       uint8_t b7:1;
>       uint8_t b6:1;
>       uint8_t b5:1;
>       uint8_t b4:1;
>       uint8_t b3:1;
>       uint8_t b2:1;
>       uint8_t b1:1;
>       uint8_t b0:1;
> #elif __BYTE_ORDER == __BIG_ENDIAN
>       uint8_t b0:1;
>       uint8_t b1:1;
>       uint8_t b2:1;
>       uint8_t b3:1;
>       uint8_t b4:1;
>       uint8_t b5:1;
>       uint8_t b6:1;
>       uint8_t b7:1;
> #endif /* big or little endian */
> } ATTRIBUTE bitfields;
>
> /* --- main --- */
> int main(void) {
>       uint8_t *val=(uint8_t*)calloc(1,1);
>       bitfields* bf = (bitfields*)val;
>       printf("Tests endianness.\n");
> #if 1 /* double check code */
>       printf("Little endian = %d, ",__LITTLE_ENDIAN);
>       printf("big endian = %d, ",__BIG_ENDIAN);
>       printf("and byte order = %d.\n",__BYTE_ORDER);
> #endif /* end of double check code. */
> #if __BYTE_ORDER == __LITTLE_ENDIAN
>       printf("This machine works in little endian.\n");
> #elif __BYTE_ORDER == __BIG_ENDIAN
>       printf("This machine works in big endian.\n");
> #endif /* big or little endian */
>
> #if 1 /* Another double check code */
>       printf("Size of value is %d ",sizeof(*val));
>       printf("and size of bit fields is %d.\n",sizeof(*bf));
> #endif /* End of the second double check code */
>       printf("\nTo understand how bits are ordered into a byte,\n");
>       printf("Give a value : ");
> #ifdef _WIN32 /* scanf() is deprecated by VS 2005. */
>       scanf_s("%hhu", val);
> #else /* no problem with this under linux */
>       scanf("%hhu", val);
> #endif /* windows or linux */
>       while ( *val ) {
>               uint8_t n = bf->b0&1;
>               printf("Given value = %d.\n", *val);
>               printf("val=%d,",n);
>               n = bf->b1&1; printf("%d,",n);
>               n = bf->b2&1; printf("%d,",n);
>               n = bf->b3&1; printf("%d,",n);
>               n = bf->b4&1; printf("%d,",n);
>               n = bf->b5&1; printf("%d,",n);
>               n = bf->b6&1; printf("%d,",n);
>               n = bf->b7&1; printf("%d from b0 to b7.\n",n);
>               printf("Give another value : ");
> #ifdef _WIN32 /* scanf() is deprecated by VS 2005. */
>               scanf_s("%hhu", val);
> #else /* no problem with this under linux */
>               scanf("%hhu", val);
> #endif /* windows or linux */
>       } /* at this time, value is 0 */
>
>       printf("Finished.\n");
>       free(val);
>       return 0;
> } /* main */
> ------ END OF CODE ------
>
> Here is the output which is now printed by this piece of code:
>
> ------ BEGINNING OF OUTPUT ------
> Tests endianness.
> Little endian = 1234, big endian = 4321, and byte order = 1234.
> This machine works in little endian.
> Size of value is 1 and size of bit fields is 1.
>
> To understand how bits are ordered into a byte,
> Give a value : 1
> Given value = 1.
> val=0,0,0,0,0,0,0,1 from b0 to b7.
> Give another value : 128
> Given value = 128.
> val=1,0,0,0,0,0,0,0 from b0 to b7.
> Give another value : 0
> Finished.
> ------ END OF OUTPUT ------
>
> So, now, as you can see, the bits of an octet are always shown beginning
> with the MSB as I wanted.
>
> However, a strange problem remains under windows.
>
> Just after printing "Finished!", the debugger shows a dialog box stating
> that the heap was corrupted during execution. Here is the message
> contained in the dialog box:
>
> ------ BEGINNING OF MESSAGE ------
> Microsoft Visual C++ Debug Library
> Debug Error!graphic 904  Program:
> c:\local\testendian\debug\TestEndian.exe
> HEAP CORRUPTION DETECTED: after Normal block (#58) at 0x00362E90.
> CRT detected that the application wrote to memory after end of heap
> buffer.
> (Press Retry to debug the application)
> ------ END OF MESSAGE ------
>
> The faulty instruction seems to be "free(val)" and I really can't figure
> out why.
>
> Of course, in this particular case, since the "free(val)" instruction is
> at the right end of the code, I could simply omit it. If I comment the
> "free(val)" line, my code smoothly ends without error message. In this
> particular case, the generated memory leak is not critical since the
> memory which is lost by the code itself will be collected soon by the
> OS.
>
> However, this is not the first time I notice this annoying behaviour.
> When such a thing occurs in the middle of a program execution, windows
> does not always complain and continues to run silently until the heap is
> totally corrupted at a later time.
>
> So please, what did I do wrong with this piece of code?
>
> I suspect the problem to come from the fact that my bitfields data
> structure exactly points to the input value because when I remove it and
> the associated code which prints the bits one by one, the heap is no
> more corrupted but how can I avoid this please?
>
> Many thanks in advance. Have a nice day. Chris D
>
> -----Original Message-----
> From: programmingblind-bounce@xxxxxxxxxxxxx
> [mailto:programmingblind-bounce@xxxxxxxxxxxxx] On Behalf Of Joseph Lee
> Sent: mardi 20 juillet 2010 14:54
> To: programmingblind@xxxxxxxxxxxxx
> Subject: RE: How should I test endianness in C or C++?
>
> Hi,
> Try using quotes instead of arrows. But first, you might want to include
> it
> as part of your project.
> Cheers,
> Joseph
>
> -----Original Message-----
> From: programmingblind-bounce@xxxxxxxxxxxxx
> [mailto:programmingblind-bounce@xxxxxxxxxxxxx] On Behalf Of Delaunay
> Christophe
> Sent: Tuesday, July 20, 2010 5:44 AM
> To: programmingblind@xxxxxxxxxxxxx
> Subject: RE: How should I test endianness in C or C++?
>
> Hi Martin and all,
>
> Many thanks for your help.
>
> In fact, what you noticed is exactly what I want to do. More precisely,
> I want to print the bits of a number always beginning with the most
> significant bit and ending with the least significant bit. In other
> words, I want to always print the bits of an octet as if it was
> represented in big endian.
>
> This is the reason why, when my code notices that it should work in big
> endian, the bitfields data structure defines bit b0 first, and when the
> code notices that it works in little endian, it defines the bitfields
> data structure with bit b7 first.
>
> In practice, this artefact is useful for code which deals with network
> protocols implemented in different platforms. The needed data structures
> are defined in some special .h file and then, it is manipulated by a
> code which is totally independent from endianness.
>
> Now, it works under linux. I posted my request on another more
> linux-dedicated list and some kind people told me that I forgot the
> following line:
>
> #include <endian.h>
>
> I added the line in my code and, under linux, it now seems to work like
> a charm.
>
> However, I also would greatly need this piece of code to work under
> windows.
>
> Under this OS, I'm compiling with Visual C++ pro 2005. The compiler
> complains that <endian.h> does not exist. What should I replace
> "#include <endian.h>" with under windows please?
>
> Many thanks. Have a nice day. Chris D
>
> -----Original Message-----
> From: programmingblind-bounce@xxxxxxxxxxxxx
> [mailto:programmingblind-bounce@xxxxxxxxxxxxx] On Behalf Of Martin Slack
> Sent: mardi 20 juillet 2010 13:19
> To: programmingblind@xxxxxxxxxxxxx
> Subject: Re: How should I test endianness in C or C++?
>
> Hi Christophe,
>
>   Although your two structs are ordered differently, the print routine
> takes
> the bits in order b0 to b7 whatever the endianness of the machine.
>
>   Corrections welcome,
>
>   Martin
>
>
> ----- Original Message -----
> From: "Delaunay Christophe" <christophe.delaunay@xxxxxxxxxxxxxxx>
> To: <programmingblind@xxxxxxxxxxxxx>
> Sent: Tuesday, July 20, 2010 8:28 AM
> Subject: How should I test endianness in C or C++?
>
>
> Hi all,
>
> Here is my piece of code:
> ------ BEGINNING OF CODE ------
> /**
>  *
>  * This small program tests and explains endianness.
>  *
>  */
>
> /* --- The needed header files --- */
> #include <stdio.h> /* for input and output */
> #include <inttypes.h> /* special integer types */
>
> /* --- Given definition --- */
> #ifdef WIN32 /* windows-like OS assumed */
> #define ATTRIBUTE
> #else /* linux-like OS assumed */
> #define ATTRIBUTE __attribute__((packed))
> #endif /* windows or linux */
>
> /* --- The byte divided into 8 bit fields --- */
> typedef struct _bitfields {
> #if __BYTE_ORDER == __BIG_ENDIAN
> uint8_t b0:1;
> uint8_t b1:1;
> uint8_t b2:1;
> uint8_t b3:1;
> uint8_t b4:1;
> uint8_t b5:1;
> uint8_t b6:1;
> uint8_t b7:1;
> #elif __BYTE_ORDER == __LITTLE_ENDIAN
> uint8_t b7:1;
> uint8_t b6:1;
> uint8_t b5:1;
> uint8_t b4:1;
> uint8_t b3:1;
> uint8_t b2:1;
> uint8_t b1:1;
> uint8_t b0:1;
> #endif /* big or little endian */
> } ATTRIBUTE bitfields;
>
> /* --- main --- */
> int main(void) {
> uint8_t val=0;
> bitfields* bf = (bitfields*)(&val);
> #if __BYTE_ORDER == __BIG_ENDIAN
> printf("This machine works in big endian.\n");
> #elif __BYTE_ORDER == __LITTLE_ENDIAN
> printf("This machine works in little endian.\n");
> #endif /* big or little endian */
> printf("To understand how bits are ordered into a byte.\n");
> printf("Give a value : ");
> scanf("%hhu", &val);
> while ( val != 0 ) {
> uint8_t n = bf->b0&1;
> printf("Given value = %d.\n", val);
> printf("val=%d,",n);
> n = bf->b1&1; printf("%d,",n);
> n = bf->b2&1; printf("%d,",n);
> n = bf->b3&1; printf("%d,",n);
> n = bf->b4&1; printf("%d,",n);
> n = bf->b5&1; printf("%d,",n);
> n = bf->b6&1; printf("%d,",n);
> n = bf->b7&1; printf("%d from b0 to b7.\n",n);
> printf("Give another value : ");
> scanf("%hhu", &val);
> } /* at this time, value is 0 */
>
> printf("Finished.\n");
> return 0;
> } /* main */
> ------ END OF CODE ------
>
> Problem: When I run this program, here is what I obtain:
> ------ BEGINNING OF OUTPUT ------
> [delaunayc@rennxlxrda013 TestEndian]$ ./TestByteOrder
> This machine works in big endian.
> To understand how bits are ordered into a byte.
> Give a value : 1
> Given value = 1.
> val=1,0,0,0,0,0,0,0 from b0 to b7.
> Give another value : 2
> Given value = 2.
> val=0,1,0,0,0,0,0,0 from b0 to b7.
> Give another value : 3
> Given value = 3.
> val=1,1,0,0,0,0,0,0 from b0 to b7.
> Give another value : 4
> Given value = 4.
> val=0,0,1,0,0,0,0,0 from b0 to b7.
> Give another value : 128
> Given value = 128.
> val=0,0,0,0,0,0,0,1 from b0 to b7.
> Give another value : 130
> Given value = 130.
> val=0,1,0,0,0,0,0,1 from b0 to b7.
> Give another value : 131
> Given value = 131.
> val=1,1,0,0,0,0,0,1 from b0 to b7.
> Give another value : 0
> Finished.
> [delaunayc@rennxlxrda013 TestEndian]$
> ------ END OF OUTPUT ------
>
> As you can see, this machine says that it works in big endian but
> presents the byte order in little endian.
>
> Therefore, I suspect my #if test to be bad but what did I do wrong
> please?
>
> The machine is a PC running Fedora 12. I compiled the above code with
> GCC version 4.4.3.
> Many thanks in advance. Have a nice day. Chris D
> __________
> View the list's information and change your settings at
> //www.freelists.org/list/programmingblind
>
>
__________
View the list's information and change your settings at 
//www.freelists.org/list/programmingblind

Other related posts: