![]() |
|
#11
|
|||
|
|||
Re: MACRO to detect big / little endianQuote:
So, if you get the bytes of the header in the right order (independent of the endianness of the machine, then you can extract the information from the individual fields. I would just read them a byte at a time in an array of chars and then examine the bytes: CPP / C++ / C Code:
Code:
(I'll let you figure out the sample rates, etc.) Now if you want to read the four bytes into a 32-bit integer, you will have to be concerned about endianness, and you could do something like the following: CPP / C++ / C Code:
Output Code:
Notice the similarity between network operations and file operations: you are reading and writing with a stream of bytes. Bytes-in are the same order as bytes-out. If you store them a byte at a time, the code will not depend on the endianness of the host. If some of the bytes have to be put together as 16-bit or 32-bit integers for some reason, you can read and write multiple bytes at a time and then use some kind of function to swap bytes if the machine architecture is differently-ended than the byte stream. Anyhow the bottom line is: Deal with bytes and there is never a need to take endianness into account. Deal with multi-byte quantities, and you may be able to use library functions (albeit not standard library functions) to help you write endian-agnostic code. We could have saved a little board bandwidth if I hadn't made the wrong guess as to what you really wanted to do. (But that's OK, I hope. I still would like to know if anyone comes up with better "macro" stuff than my negative comments.) Regards, Dave |
|||
|
#12
|
|||
|
|||
Re: MACRO to detect big / little endianI don't know of a good macro way of testing big/little endianness, but here is an easy to use C way:
CPP / C++ / C Code:
Output: Code:
:davis: |
|
#13
|
|||
|
|||
Re: MACRO to detect big / little endianQuote:
The point is that in order to know about endianness, you have to be able to examine something that you put into memory (or somehow know the contents of some memory locations, regardless of how they got there) and that you know has different values for one strategically placed byte than for other bytes. So what's the problem with making a macro out of it? You could make the macro that consists of a block, inside of which you declare an integer data type variable and store something. But I don't see how to make the result of invoking such a macro be the value of an expression that you could use in an expression like if (is_big_endian()){...}. I don't know of a particularly important (practical) reason to knock ourselves out trying to make it a macro instead of a function, but I don't think it hurts to think about such things from time to time. I mean, as much as I have expressed my disdain for macros in general, sometimes you are faced with OPC (Other People's Code) that is rife with insipid, useless, confusing macros and you have to try to make heads-or-tails out of it. So thinking about such things ahead of time could give you a little edge. Sometimes you may even see some code where intricate, clever, extremely time-efficient or memory-efficient, if somewhat obfuscatory, macros do a fantastic job, but it seems to me that most (all??) of them that I can remember lately could have been done as effectively and more safely with in-line functions. Regards, Dave Footnote: As far as being "easy to use," they are all "easy to use": if (is_big_endian()){...}, right? |
|
#14
|
||||
|
||||
Re: MACRO to detect big / little endianHello everyone.
Dave said: I have some questions from a rather previous post in this thread. Pardon me for taking the flow a bit backwards, but I hope you guys understand Quote:
Quote:
Then again, in my original program I had compared 'cptr' directly with NULL. And you corrected me to have '*cptr' compared with '0' instead. Well...does dereferencing 'NULL' return a value '0'? Quote:
If thats the case, then *cptr would give the 'item' stored at the lowest memory location for the variable test_var and if thats zero then it means little endian architecture and if it isn't then it means it is big endian architecture. Quote:
waiting for ur answers __________________
Hope to hear from you guys! -------------------------------------------------- Best Regards, Aijaz Baig. |
|
#15
|
||||||||
|
||||||||
Re: MACRO to detect big / little endianQuote:
A literal string is not an array of char. The official terminology for what I called a "literal string" is actually a "character string literal". I hope that was not a point of confusion. (Note that there is also a thing called a "wide string literal" with wide chars. I am not addressing that here, and I will not address it.) When I refer to "literal string" or "character string" I am referring to the following From the C standard (ISO/IEC 98/99, Section 6.4.5, Paragraph 2) Quote:
The string literal resides somewhere in program memory, and consists of the sequence of chars that you put inside the quote marks and is followed by a byte whose bits are all zero. Quote:
The term "null character" (lower case "null") is defined in the C standard in the following sentence (ISO/IEC 9899, Section 5.2.1, Paragraph 2): Quote:
Now, one example of a character string would be stuff inside the quote marks of the string literal in the following example: CPP / C++ / C Code:
The second statement does two things: 1. It causes the following six chars to be stored somewhere in program data space (it should be read-only, but not all compilers enforce the read-only part): 'H', 'e', 'l', 'l', 'o', '\0' (That last one is a byte whose bits are all zero. In other words: it is a null byte.) 2. Then it sets the value of cptr equal to the address of the 'H' character in the string literal. Now when you dereference cptr, you are referring to the memory location where the 'H' was stored. Quote:
Dereferencing NULL is always (that's always) an error. It may or may not cause a run-time error, but it "usually" does, I think. NULL is a macro, which is one of the things that is defined whenever you include <stdio.h> in your program. From ISO/IEC 98/99 Section 7.17: "The macros are NULL which expands to an implementation-defined null pointer constant" Now, from IEC/ISO 98/99, Section 6.3.2.3, Paragraph 2: "An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function." In other words NULL is defined by #define NULL ((void *)0) For Linux and all versions of Windows for which I have (or have had) compilers, a pointer with value NULL turns out to have all zeros as its value. This is not necessarily true, but it "just happens to be" so for my implementations. But that is implementation-defined. Some systems might have something else. So, comparing an integer with NULL may actually give different results that comparing an integer with an integer zero. On the other hand, comparing a pointer with 0 (even without the cast), is OK, since that is defined to be an null pointer constant. Is it just me, or does anyone else think that this is a little ambiguous? Go figure. (And see the Footnote.) However, back to your question: It is not illegal or in any way improper to compare a pointer with NULL. It simply is not useful in this case, since we already know that cptr is not equal to NULL. Why do I say that about the value of cptr? Well: 1. cptr was declared as a pointer to char in that function. 2. The value of cptr was set equal to the address of another variable. 3. No address will have a value of NULL 4. Nothing has changed the value of cptr since the assignment statement. 5. Therefore, the value of cptr in that statement can not be NULL QED What you obviously needed to do was to dereference cptr, since your routine needed to determine if the char that was being pointed to by cptr was zero. Summary: Consider the expression being tested by the following CPP / C++ / C Code:
Consider the following: CPP / C++ / C Code:
Now, sometimes you see something like the following in programs, where people really mean the previous expression CPP / C++ / C Code:
"One of the following shall hold: — both operands have arithmetic type; — both operands are pointers to qualified or unqualified versions of compatible types; — one operand is a pointer to an object or incomplete type and the other is a pointer to a qualified or unqualified version of void; or — one operand is a pointer and the other is a null pointer constant." Now for implementations that I have, the expression turns out to be the equivalent of the second example when I run the following example code. So, a relational expression involving an integer and a pointer are not allowed. My Borland compilers don't complain about the expression of example 3, but GNU gcc does. It gives a warning about comparison between pointer and integer. Microsoft compilers also give warnings to the effect that 'int' differs in levels of indirection from 'void *' The fact that NULL is a macro actually prevents the compiler from knowing that it is illegal, and in all cases an executable is created (and example 3 "just happens" to work the same way as example number 2 for my compilers). CPP / C++ / C Code:
Output: Code:
Quote:
CPP / C++ / C Code:
1. If that implementation stores integers as big-endian , the four bytes are stored in the following order: 0x00, 0x00, 0x00, 0x01. Therefore *cptr is equal to zero. 2. If that implementation stores integers as little-endian, the four bytes are stored consecutively in the following order: 0x01, 0x00, 0x00, 0x00. Therefore *cptr is equal to 1. Quote:
That's why, in introductory computer science courses, when the professor talks about such things as big-endian and little-endian, the all-knowing C.S. sophomores roll their eyes and say, "Well, that's just too weird for words. I mean, after all, I taught myself BASIC programming on my grandpa's Apple II when I was, like, eight years old, and since I have never heard of such a thing, it is obviously not important. Or, actually, the professor is some kind of nut case who obviously doesn't know what he/she is talking about." I hate to repeat myself (again), but byte-swapping is only important when you have stored things a byte a time and you want to retrieve four consecutive bytes as a 32-bit int. Or vice versa. Suppose I have a binary file whose first four bytes are 0x12, 0x34, ix56, 0x78. (Or I receive that byte stream from a communications channel.) I store the four bytes into memory in the order in which they were received into a character array. I know that those four bytes actually make up a 32-bit integer and I want to know the value of the integer. Is it 0x12345678, or is it 0x78563412? I have to know whether the bytes were written to the file in big-endian order or little-endian order. (Or, at least, I have to know whether the bytes in the file have the same endianness of the machine that is converting them to an integer.) File standards (like the mp3 format definition) specify what kind of endianness is used to write multi-byte quantities. Essentially all network standards specify that multi-byte quantities are sent in big-endian order. When you write a program to read (or write) an mp3 file, or when you write a network (sockets) program to convert a 32-bit integer to the four bytes if an IPv4 address for transmission in an IP packet or when you convert the 16-bit port address to the two bytes that go into the struct whose address you feed to the connect() function (and will eventually be send in the packet), you must take endianness into consideration. Traditional network functions like the ones I enumerated will help you write source code that will work equally well even if it is compiled on another machine whose endianness is different from yours. Not doing network programming? Not doing mp3 (or .wav or .bmp or .ttf or...) programming? Don't worry about implementing special code that deals with indianness. Writing multi-byte integers to binary files? If you know (absolutely know) that no one will ever want to read that file on a different-endian machine, then it might be OK to ignore endianness issues. Just make sure that you know that. Text files? Endianness is never an issue, since everything is written a byte at a time. (That's why I always---well usually always---prefer text files over binary for generic programs.) Regards, Dave Footnote: The formulator(s) of the C++ standard corrected the potential difficulties associated with the C definition for NULL as follows. Instead of quoting from the several sections of the C++ standard, I will go to good old Wikipedia: http://en.wikipedia.org/wiki/C++0x "In C, NULL is a preprocessor macro defined to be ((void*)0) or 0. In C++, implicit conversions from void* to other pointer types is not allowed, so something as simple as char* c = NULL would fail to compile under the former definition. To fix this, C++ ensures that NULL expands to 0, which as a special case is allowed to be converted to any pointer type. This interacts poorly with the overloading mechanism. For instance, suppose a program has declarations void foo( char* ); void foo( int ); and then calls foo(NULL); this will call the foo(int) version, which is almost certainly not what the programmer intends." So, even in C++, where the ambiguity of the definition of NULL has been removed, it is still possible for a careless or unknowing programmer to write bad code. Yes, it's true. I know that it's hard to believe, but you can actually write bad code in C++ (I wanted to put an exclamation point at the end of the previous line, but then someone would have asked what "C++ factorial" means.) ---davekw7x |
Recent GIDBlog
Programming ebook direct download available by crystalattice
| Thread Tools | Search this Thread |
| Rate This Thread | |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Help analyzing a linked list program | aijazbaig1 | C Programming Language | 22 | 01-Aug-2007 11:19 |
| how to detect mouse click in child window created by CHTMLEDITVIEW | terr | MS Visual C++ / MFC Forum | 0 | 08-Sep-2006 14:12 |
| difference between inline function and macro function | gemini_v440 | C++ Forum | 2 | 25-Mar-2006 21:36 |
| SWAP macro | alcoholic | C Programming Language | 4 | 15-Jan-2006 18:39 |
| Changing big/little endian | Dream86 | C++ Forum | 3 | 24-Jul-2005 21:13 |
Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The