GIDForums  

Go Back   GIDForums > Computer Programming Forums > C Programming Language
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read
 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 24-Aug-2007, 00:15
ahbi82 ahbi82 is offline
Regular Member
 
Join Date: Jul 2006
Posts: 325
ahbi82 has a spectacular aura aboutahbi82 has a spectacular aura about

MACRO to detect big / little endian


May i know how can i write a marco to detect little endian format.

I know to do it using a function. But to simpify things, i would like to write a macro to do it.


Thanks in advance.
  #2  
Old 24-Aug-2007, 09:33
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 6,153
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: MACRO to detect big / little endian


Quote:
Originally Posted by ahbi82
I know to do it using a function.
So: Show us. Maybe it's easy to make the macro from the function, but I would like to see what you have in mind. Maybe it can be converted (and, maybe, not).
Quote:
Originally Posted by ahbi82
But to simpify things, i would like to write a macro to do it.

I'm not sure how making it a macro will "simplify" it, but I am willing to learn.
Regards,

Dave
  #3  
Old 25-Aug-2007, 01:22
ahbi82 ahbi82 is offline
Regular Member
 
Join Date: Jul 2006
Posts: 325
ahbi82 has a spectacular aura aboutahbi82 has a spectacular aura about

Re: MACRO to detect big / little endian


Quote:
Originally Posted by davekw7x
So: Show us. Maybe it's easy to make the macro from the function, but I would like to see what you have in mind. Maybe it can be converted (and, maybe, not).


I'm not sure how making it a macro will "simplify" it, but I am willing to learn.
Regards,

Dave

CPP / C++ / C Code:
unsigned char test_endian( void )
{
    int test_var = 1;
    unsigned char test_endian* = (unsigned char*)&test_var;

    return (test_endian[0] == NULL);
}


I wanted make a macro because, before i want the decoder to know the endianess upon startup. If not i would need to check at every function that i invoke in the decoder.

May some guys will have better ideas!!!

Thanks in advance!!
  #4  
Old 25-Aug-2007, 04:53
aijazbaig1's Avatar
aijazbaig1 aijazbaig1 is offline
Member
 
Join Date: May 2006
Location: India
Posts: 174
aijazbaig1 has a spectacular aura aboutaijazbaig1 has a spectacular aura about

Re: MACRO to detect big / little endian


Hello There.
To begin with let me direct you towards this post from this thread that it is not a good idea to use a macro when a function can do the same job. Thnks for the tip dave!!..I still remember it!!

Well,moving on to ur function...I doubt the correctness of syntax of the following declaration.
CPP / C++ / C Code:
unsigned char test_endian* = (unsigned char*)&test_var;
Why is the '*' after the variable test_endian?..maybe I need to know more about this or may be this was a typo..ill assume the latter. Again this variable has the same name as the function itself. Are u trying to have a pointer to the very same function inside the function? What if you try to modify this pointer inside this function. This inner variable's scope is only within this function whereas the function is visible even outside.Hmm..gets confusing for sure.

Further you declare the function to return an unsigned char as its return value. However this comparison statement
CPP / C++ / C Code:
[(test_endian[0] == NULL)
has a value of either one or zero I think. So the return value should have been int..(or perhaps bool..i dunno much if C has any bool type variable or not). By the way, using test_endian[0] is weird here!!..cuz its a function -...

I am running this on a sparc (ultra 10) so i know it is big endian. However does anybody know how C actually stores the data in memory. This should be machine dependent so the big endian machines store the higher order bytes in higher memory locations.

But I wonder why you use the NULL character to test the endianness. Does C end all variables with the NULL character?I used to think this is only true incase of strings..i.e. char arrays as C would automatically append a NULL character after the last location. But for int?!

On trying to compile this function into an executable called endianness and heres what i get from my compiler:
Code:
gcc -std=c99 -Wall -W -pedantic -c endianness.c -o endianness.o endianness.c: In function `test_endian': endianness.c:6: warning: ISO C forbids nested functions endianness.c:6: error: syntax error before '*' token endianness.c:8: error: subscripted value is neither array nor pointer endianness.c:5: warning: unused variable `test_var' make: *** [endianness.o] Error 1
By the way,heres how I would accomplish the task:
CPP / C++ / C Code:
#include <stdio.h>

int test_endian(); //function prototype

int main()
{
    puts("lets test the endianness of this machine");
    int end_flag = test_endian();
    if (end_flag) puts("this machine is little endian");
    else puts("this machine is big endian");
    return 0;
}

int test_endian( void )
{
    int test_var = 1;
    char *cptr = (char*)&test_var;

    printf("on this machine the sizes of int and char are %d and %d respectively\n",sizeof(int),sizeof(char));
    return (cptr == NULL);
}

Well...u need to tell us how do YOU plan to test the endianness..have u come up with an idea. I'd be eager to know it.
__________________
Hope to hear from you guys!

--------------------------------------------------

Best Regards,
Aijaz Baig.
Last edited by aijazbaig1 : 25-Aug-2007 at 06:16. Reason: adding some source code
  #5  
Old 25-Aug-2007, 08:49
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 6,153
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: MACRO to detect big / little endian


Quote:
Originally Posted by aijazbaig1
it is not a good idea to use a macro ...
Sometimes there are reasons to want to use a macro; they are not always good reasons. Anyhow, I will address the macro issue in a separate post. Let's get to the functionality of the function first.
Quote:
Originally Posted by aijazbaig1
I doubt the correctness of syntax of the following declaration.
...may be this was a typo..ill assume the latter.
That would be my guess, since it can't possibly compile with any standard C compiler.

Quote:
Originally Posted by aijazbaig1
Again this variable has the same name as the function itself.....gets confusing
I think it is bad style, since it may be confusing to us mere humans, but it isn't actually incorrect. The declaration inside the function hides previous declarations of any variables with the same name, so it could work.

Quote:
Originally Posted by aijazbaig1
Further you declare the function to return an unsigned char as its return value. However this comparison statement
CPP / C++ / C Code:
(test_endian[0] == NULL)
has a value of either one or zero I think.

An unsigned char is an integer data type. As an eight-bit quantity it can have any value from zero up to and including 255(decimal), so it certainly can take on values of zero and one.
Quote:
Originally Posted by aijazbaig1
I am running this on a sparc (ultra 10) so i know it is big endian
I am very happy that you told us that, since you can test any programs like this that I can't, since I only have Intel/AMD x64 platforms. I'll get back to you in a minute
Quote:
Originally Posted by aijazbaig1
However does anybody know how C actually stores the data in memory. This should be machine dependent so the big endian machines store the higher order bytes in higher memory locations.

Well, that's the point of this little exercise: Create source code that can be compiled on any kind of platform and upon execution report on its endianness. Note, however that there are actually three kinds of endianness, not just two. See footnote. For the moment, let's just concentrate in big/little.

Another question might be whether there is a way to create a program (with macros or whatever) for which the endianness could be determined at compile time. In other words, have the compiler spit out an error or some other kind of message that tests the endianness when compiling. I don't think it can be done portably (with standard C and the standard C library), and I would really (really) like to hear from anyone who knows how.

Let's get back to the issue of detecting endianness at run time (with portable standard C and the standard C library).
Quote:
Originally Posted by aijazbaig1

But I wonder why you use the NULL character to test the endianness.
People sometimes think that NULL is a synonym for zero. Actually, NULL is defined as a pointer whose value corresponds to an integer with value zero cast as a pointer. I think that if you want to know whether an integer data type is zero, it would be better to compare it with zero rather than NULL. However, in this case comparing it with NULL wouldn't cause it not to work.
Quote:
Originally Posted by aijazbaig1
Does C end all variables with the NULL character?
No.
Quote:
Originally Posted by aijazbaig1
I used to think this is only true incase of strings..i.e. char arrays as C would automatically append a NULL character after the last location.
No it doesn't.
Literal strings have a zero byte at the end (defined as a byte whose bits are all zero), and sometimes we speak of a null-terminated "C-style" string. But that's just English, not C. Lower-case "null" is not defined as an identifier in C or anywhere in the standard C library. Upper-case "NULL" is #defined as a pointer in <stdio.h> (or some file that gets included when you include <stdio.h>).
Quote:
Originally Posted by aijazbaig1

On trying to compile this function into an executable called endianness and heres what i get from my compiler:

Here is the original program to which I have made minimal changes in order to get an absolutely clean compile according to the C89 standard:
CPP / C++ / C Code:
#include <stdio.h>

unsigned char test_endian(void);

int main()
{
    if (test_endian()) {
        printf("This machine is big-endian.\n");
    }
    else {
        printf("This machine is little-endian.\n");
    }

    return 0;
}

/* 
 * returns 1 if the machine is big_endian
 * returns 0 if the machine is not big_endian
 * (Ignores the possibility of middle_endian.)
 */
unsigned char test_endian( void )
{
    int test_var = 1;
    unsigned char *test_endian = (unsigned char*)&test_var;

    return (test_endian[0] == 0);
}

My output:
Code:
This machine is little-endian.
Now here are some style changes that I would consider:

1. Give the function a meaningful name. Without the comment before the function definition, I would actually have to go through the logic to know what to expect out of the function. Now, comments are good, but I think that a proper selection of a name of the function to make it more-or-less self-documenting is even more important. So, since the function as written returns the C language equivalent of "true" for big-endian machines, I would probably name the function "is_big_endian()" or some such thing.

2. As we already agreed, creating a variable within the function that has the same name as the function could be confusing to us humans, I would give it another name.

3. Other minor changes are just a matter of habit. For one thing, unless I have a good reason to use something else, I just use ints for function return types, etc. No particular reason these days (but once upon a time with a Small C compiler for a Z-80, I found that the compiled code did more work dealing with chars than it did dealing with ints).

CPP / C++ / C Code:
#include <stdio.h>

int is_big_endian(void);

int main()
{
    if (is_big_endian()) {
        printf("This machine is big-endian.\n");
    }
    else {
        printf("This machine is little-endian.\n");
    }

    return 0;
}

/* 
 * returns 1 if the machine is big_endian
 * returns 0 if the machine is not big_endian
 * (Ignores the possibility of middle_endian.)
 */
int is_big_endian( void )
{
    int i = 1;
    unsigned char *pc = (unsigned char*)&i;

    return (pc[0] == 0); /* most significant byte is stored first for big_endian */
}
As I mentioned, I have no way of testing this code with big-endian platforms (although I did something like this once on an embedded system with an Intel IXP425 big-endian processor).

Note that there are slight variations on the way that the byte-order in memory can be tested. You can use something like
CPP / C++ / C Code:
    union {
        int i;
        unsigned char cc[sizeof(int)];
    } int_char;
    int_char.i = 1;
    return (int_char.cc[0] == 0); /* most significant byte is stored first for big_endian */

Quote:
Originally Posted by aijazbaig1
By the way,heres how I would accomplish the task:...

Well, this is why it's hard to develop something like this without being able to test: I compiled and ran on my little-endian platform and here is the output:
Code:
lets test the endianness of this machine on this machine the sizes of int and char are 4 and 1 respectively this machine is big endian

What happened?

1. This statement always returns a value of zero:
CPP / C++ / C Code:
    return (cptr == NULL);

cptr is a pointer whose address is that of the variable test_var. Its value will never be NULL. (That's part of the C standard.)

Maybe you meant:
CPP / C++ / C Code:
    return (*cptr == 0);
This would return one if the most significant byte of test_var is stored first, and it would return zero if the least significant byte of test_var is stored first. So now, it is possible to return a value that depends on the endianness of the machine.

One other little 'gotcha' is that the logic of your main program assumes that a return value of zero indicates a big_endian architecture. (That's why I suggested a more meaningful name for the function.)

To get your function to work without changing your main program you could change the return statement to
CPP / C++ / C Code:
    return (*cptr != 0);

Anyhow, with that single change, here's what I get:
Code:
lets test the endianness of this machine on this machine the sizes of int and char are 4 and 1 respectively this machine is little endian

Thank you for posting and thank you for giving us a way to test on big-endian machines. (Note that users of older Macintosh computers---the one with a PowerPC CPU---can also test the big_endian functionality.)

Regards,

Dave


Footnote: The good old PDP-11 (a 16-bit machine, and the first really successful minicomputer---the one that ate IBM's lunch back in the 1970's) had a different way of storing 32-bit integers:http://en.wikipedia.org/wiki/Endianness#Middle-endian. For the purposes of this post, I am ignoring that kind or architecture.
  #6  
Old 25-Aug-2007, 11:22
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 6,153
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: MACRO to detect big / little endian


Quote:
Originally Posted by ahbi82
I wanted make a macro because...
aijazbaig and I gave rather lengthy responses that addressed your function code. I wanted to give a separate answer here for the macro question
Quote:
Originally Posted by ahbi82

I wanted make a macro because, before i want the decoder to know the endianess upon startup. If not i would need to check at every function that i invoke in the decoder.
I can't understand what would be different about the way you would use a macro, compared to the way you would use a function. You would still have to test, somehow, every multi-byte data item that you transferred back and forth between memory and whatever function that you have that requires a particular endianness.

Every serious C compiler has functions that are used in network applications to swap bytes (if necessary) as data are transferred into and out of memory to make sure the bytes in and out of network functions are in network order (big-endian). Note that these functions are not standard C (or C++) library functions as defined in the standard language specification. That's why different header files might be used for different compiler installations.

The way it works is that somewhere in files that you include when you use the network functions, there is a machine-dependent #define (or some other mechanism) that works for that particular target architecture so that one version of each of the functions (actually, they might be macros) htonl(), htons(), ntohl() and ntohs() will swap bytes if the target architecture is little-endian but another version of each will leave them in the same order if the target is big-endian. Your application code always uses these functions when endianness is an issue. (Not for all data store and retrieve; just where you have to know that the object is big-endian.)

The actual mechanism that determines which version of each function to use is hidden from the application programmer and is taken care of automatically by whatever configuration program was run when the compiler (and library) itself was installed for a particular target machine. (In other words, the compiler is set up to create code for whatever-endian machine is the target, and the functions are selected accordingly.)

So: first of all do "man htonl" on your system and see if you get anything. It should show you what you would have to #include in order to use these functions.

Windows programmers would #include winsock2.h>. On my Linux systems (and on Windows XP using cygwin/gcc), I #include <arpa/inet.h>, and that's what I show in the example below.

Note that on a big-endian machine, htonx() and ntohx() don't actually have to do any work, and as a result, network I/O can actually be more efficient than on little-endian machines. (A fact that I wish the good designers at Intel would have taken into account when they designed the early 80xx chips. We might never have had to worry about endianness. Although, I will concede that, in the context of the early 1970's there might have been important reasons to commit to little-endian architecture. Motorola didn't think so.)

Here's a little program that shows use of ntohl(), and the output shows what happens on a little-endian machine:

CPP / C++ / C Code:
/* if your installation doesn't have <stdint.h>, then
 * use a typedef so that uint32_t denotes an unsigned
 * 32-bit integer data type
 * For example, if you know your system has 32-bit integers:
 *
 * typedef unsigned int uint32_t;
 *
 * If your system doesn't have <arpa/inet.h>, then
 * include something that allows you to use htonl()
 *
 */
#include <stdio.h>
#include <stdint.h>
#include <arpa/inet.h>

void showbytes(uint32_t);
int main()
{
    uint32_t x, y;

    x = 0x12345678; /* these bytes are stored in system-dependent order */
    printf("x = 0x%08x\n\n", x);
    printf("Here are the bytes of x (machine order): ");
    showbytes(x); 
    y = htonl(x);
    printf("\nHere are the bytes of y (network order): ");
    showbytes(y); 
    return 0;
}

void showbytes(uint32_t data)
{
    unsigned char *cp = (unsigned char *)&data;
    int i;
    for (i = 0; i < 4; i++)  {
        printf("0x%02x ", cp[i]);
    }
    printf("\n");
}


Output on my little-endian systems:
Code:
x = 0x12345678 Here are the bytes of x (machine order): 0x78 0x56 0x34 0x12 Here are the bytes of y (network order): 0x12 0x34 0x56 0x78

If necessary, make whatever changes to include the proper header file to get it to compile. If your machine has a big-endian architecture, the bytes of x and the bytes of y should be the same: 0x12 0x34 0x56 0x78

Regards,

Dave
Last edited by davekw7x : 25-Aug-2007 at 12:11.
  #7  
Old 25-Aug-2007, 12:50
ahbi82 ahbi82 is offline
Regular Member
 
Join Date: Jul 2006
Posts: 325
ahbi82 has a spectacular aura aboutahbi82 has a spectacular aura about

Re: MACRO to detect big / little endian


First of all, i would like to apologise for the type error and its

CPP / C++ / C Code:
unsigned char* test_endian = (unsigned char*)&test_var;


For anness byte addressing, the test_endian is pointing to the first byte of the test_var which is 4 bytes (int). To test for endiannees, we need to check for the byte addressing.

I intended to use a macro because, i wanted to determine the endianness of that platform, before i invoke my decoder. It would add to the decoding time IF i check for endianess in every byte operation.

And of course, aijazbaig1 do u know whats endianness, the comments u gave dun really involved my query. Or rather maybe you are proving my errors. Anyway, i am not asking anyone to check for my errors, but to get the idea of what i am getting at.


Once again, i would like to THANKS dave previous comments!!!!!

  #8  
Old 25-Aug-2007, 13:03
ahbi82 ahbi82 is offline
Regular Member
 
Join Date: Jul 2006
Posts: 325
ahbi82 has a spectacular aura aboutahbi82 has a spectacular aura about

Re: MACRO to detect big / little endian


THANKS for all ur comments.

I am not working on programs for networking. The decoder works on an embedded system. Thus i would like to create a prtable decoder, if for future the decoder can be portable if i use a different chip.
  #9  
Old 25-Aug-2007, 13:18
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 6,153
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: MACRO to detect big / little endian


Quote:
Originally Posted by ahbi82
THANKS for all ur comments.

I am not working on programs for networking. The decoder works on an embedded system. Thus i would like to create a prtable decoder, if for future the decoder can be portable if i use a different chip.

I thought that the reason you needed a function or macro to determine system endianness was because getting 32-bit ints (or 16-bit ints) into and out of memory would require byte-swapping for little-endian machines but not for big-endian ones (or some such thing). Maybe I missed something. It wouldn't be the first time. See footnote.

The suggestion was: If your system has htonl() and ntohl(), you can use them to write code that "automatically" decides whether byte-swapping is necessary and does whatever is necessary to get things from memory into a register in big-endian order so that the mathematical algorithm can work as expected. (All without having to change source code for different target architectures.)

Since many libraries for embedded systems have htonl() and ntohl() (if you know where to look for them), I thought you might be interested in using them for your application, thus eliminating the need for your source code having to use the endianness-detecting function for each and every memory access.

How about this: Give an example of where you would use your function (or macro) that influences the code in a way that depends on endianness of the target architecture. (If the endianness of the target doesn't affect the functionality, why would you want to test for it?)

Regards,

Dave

We have already answered your first question as far as I know: I don't believe there is a portable way (using standard C language and libraries) to write a macro that, as an expression, evaluates to one value for a big-endian machine and another value for a little-endian machine. There are ways to write functions that correctly do this. Your function wasn't quite right, but I showed how to make it work, and I showed another, similar, way (there are, undoubtedly, other ways).

Of course, another way would be to write the program so that it reads and writes bytes (i.e. chars) from and to memory instead of ints or other multi-byte quantities. Then endianness need never raise its ugly head.
  #10  
Old 25-Aug-2007, 13:26
ahbi82 ahbi82 is offline
Regular Member
 
Join Date: Jul 2006
Posts: 325
ahbi82 has a spectacular aura aboutahbi82 has a spectacular aura about

Re: MACRO to detect big / little endian


Quote:
Originally Posted by davekw7x
How about this: Give an example of where you would use your function (or macro) that influences the code in a way that depends on endianness of the target architecture. (If the endianness of the target doesn't affect the functionality, why would you want to test for it?)

Regards,

Dave

For example. if i am decoding a music format, let say mp3, i need to do byte or bit accessing to get the data to be decoded. First of all the magic number for the header to determine what music format that file really is and perform the correct decoding method.

I would look for the 2 functions that u recommanded form the mannual.

THANKS AGAIN!!!!!!
 


Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Help analyzing a linked list program aijazbaig1 C Programming Language 22 01-Aug-2007 10:19
how to detect mouse click in child window created by CHTMLEDITVIEW terr MS Visual C++ / MFC Forum 0 08-Sep-2006 13:12
difference between inline function and macro function gemini_v440 C++ Forum 2 25-Mar-2006 20:36
SWAP macro alcoholic C Programming Language 4 15-Jan-2006 17:39
Changing big/little endian Dream86 C++ Forum 3 24-Jul-2005 20:13

Network Sites: GIDNetwork · GIDApp · GIDBlog · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 01:27.


vBulletin, Copyright © 2000 - 2014, Jelsoft Enterprises Ltd.