Endian defines

I’d like to request a small addition to the SDL code regarding endian
defines. Currently we have these:

#define SDL_LIL_ENDIAN 1234
#define SDL_BIG_ENDIAN 4321

#if
#define SDL_BYTEORDER SDL_LIL_ENDIAN
#else
#define SDL_BYTEORDER SDL_BIG_ENDIAN
#endif

This allows you do check using something like:

if (SDL_BYTEORDER == SDL_LIL_ENDIAN)

However I’d like to really harness the power of defines and use something
like:

#ifdef SDL_IS_LIL_ENDIAN
value = *((Uint16 *) byte_ptr);
#else
value = byte_ptr[0] | (byte_ptr[1] << 8);
#endif

This would be must better in a critical loop, not having to waste CPU cycles
running checking code. Instead, the compiler can just put in the code
required for the platform directly instead. With the current defines in
place, you can’t have the compiler make these decisions I don’t think,
unless maybe this would work:

#if (SDL_BYTEORDER - SDL_LIL_ENDIAN)

But that could be confusing to someone trying to read the code.

Comments? Feedback?

-Jason

(quote rearranged)

#ifdef SDL_IS_LIL_ENDIAN
value = *((Uint16 *) byte_ptr);
#else
value = byte_ptr[0] | (byte_ptr[1] << 8);
#endif

This would be must better in a critical loop, not having to waste CPU cycles
running checking code. Instead, the compiler can just put in the code

SDL_BYTEORDER, SDL_LIL_ENDIAN and SDL_BIG_ENDIAN are compile-time
constants. “if(SDL_BYTEORDER == SDL_LIL_ENDIAN)” becomes
"if(1234 == 1234)" or “if(1234 == 4321)”. If it’s false, the unused
code won’t be included at all (with a sane compiler), and there is
no conditional at all.

For example:

01:23am glenn at zewt/3 [~] cat foobar.cc
#include <stdio.h>
main()
{
if( 1 == 0 )
printf(“hello world\n”);
}

01:23am glenn at zewt/3 [~] g++ foobar.cc
01:24am glenn at zewt/3 [~] strings a.out|grep hello
01:24am glenn at zewt/3 [~]

The compiler knows that the “printf” can never be reached. The call to
"printf" and the string constant “hello world” are removed.

However I’d like to really harness the power of defines and use something
like:

Harness? You seem to think inline preprocessor directives are a good
thing. They’re not! :slight_smile: Clean code has as few #ifs in the source as
possible; they’re ugly and cumbersome. (Take a look at the "infozip"
source for an extreme example of how bad code can get due to #ifdefs.)

Once you understand compiler optimizations, they’re very rarely needed,
especially with C++'s templates (“min” and “max” should not be macros!).On Fri, Jan 16, 2004 at 04:00:16PM -0600, Jason Hoffoss wrote:


Glenn Maynard

> ("min" and "max" should not be macros!).

cough blush

:slight_smile:

-bill!On Thu, Jan 22, 2004 at 01:33:55AM -0500, Glenn Maynard wrote:

Jason Hoffoss wrote:

#ifdef SDL_IS_LIL_ENDIAN
value = *((Uint16 *) byte_ptr);
#else

I assume byte_ptr is a (u_int8_t *). You shouldn’t dare to cast it to
a (u_int16_t *) unless the CPU is a x86 or byte_ptr points to an
address which is properly aligned on a 2 byte boundary. Otherwise, the
CPU will be pretty pissed off and either crash your program or make
it real sloooooooow. Try an Alpha for example.–
Christian
-------------- next part --------------
A non-text attachment was scrubbed…
Name: not available
Type: application/pgp-signature
Size: 186 bytes
Desc: not available
URL: http://lists.libsdl.org/pipermail/sdl-libsdl.org/attachments/20040122/8dc8cc4c/attachment.pgp

Huh? You realize you’re nitpicking dummy code, right? (Programs that
really do this usually increment byte_ptr two at a time, so it remains
even, but since this is only an example, that code doesn’t exist.)On Thu, Jan 22, 2004 at 03:09:08PM +0100, Christian Biere wrote:

Jason Hoffoss wrote:

#ifdef SDL_IS_LIL_ENDIAN
value = *((Uint16 *) byte_ptr);
#else

I assume byte_ptr is a (u_int8_t *). You shouldn’t dare to cast it to
a (u_int16_t *) unless the CPU is a x86 or byte_ptr points to an
address which is properly aligned on a 2 byte boundary. Otherwise, the
CPU will be pretty pissed off and either crash your program or make
it real sloooooooow. Try an Alpha for example.


Glenn Maynard

Glenn Maynard wrote:

#ifdef SDL_IS_LIL_ENDIAN
value = *((Uint16 *) byte_ptr);
#else
value = byte_ptr[0] | (byte_ptr[1] << 8);
#endif

At a second reading, I don’t understand the purpose of the above unless
SDL_IS_LIL_ENDIAN should read as SDL_IS_BIG_ENDIAN.

SDL_BYTEORDER, SDL_LIL_ENDIAN and SDL_BIG_ENDIAN are compile-time
constants. “if(SDL_BYTEORDER == SDL_LIL_ENDIAN)” becomes
"if(1234 == 1234)" or “if(1234 == 4321)”. If it’s false, the unused
code won’t be included at all (with a sane compiler), and there is
no conditional at all.

Well, if you use preprocessor statements, the compiler can be as simple
as possible because it won’t even see the code which was already
thrown away by the preprocessor.

#include <stdio.h>
main()
{
if( 1 == 0 )
printf(“hello world\n”);
}

01:23am glenn at zewt/3 [~] g++ foobar.cc

It’s seldom a good idea to compile C code with a C++ compiler. There are
enough corner cases where the same code has different semantics.

Harness? You seem to think inline preprocessor directives are a good
thing. They’re not!

As long as people know what they’re doing, you can’t blame them.

Clean code has as few #ifs in the source as possible; they’re ugly and
cumbersome.

There’s no benefit of replacing all #if's withif’s. Preprocessor
directives are only bad if they tear the C code too much apart. In
that case it’s much better to write a complete function or even a
module for different cases or just restructure the code.

Once you understand compiler optimizations, they’re very rarely needed,
especially with C++'s templates (“min” and “max” should not be macros!).

C99 has inline and if you can accept a C99 compiler as requirement, you
can, of course, use this feature to replace macros by inline functions
for the benefit of type checking. Unfortunately, GCC introduced inline
for C before C99 and therefore both have different semantics, unless
you use -std=c99 for GCC 3.x.
Last but not least, macros shall always be in all-caps (MIN, MAX) to
remind you bewaring side-effects unless it doesn’t matter whether
it’s a macro or not (macros don’t have addresses, of course) like

#define MAGIC_NUMBER 0xDEADBEEFU

In this case it’s much better to use `enum’ though because you’ll
see the symbolic values in the debugger instead of the raw numbers
and it also allows a stronger type system if you want to.

The nice thing about the MIN and MAX macros is, that it doesn’t
matter whether you use it with addresses, ints, floats etc. and you
only have to write them once. You can do that with C++, you can’t
do it with Java (unless you use a pre-processor which is quite possible).> On Fri, Jan 16, 2004 at 04:00:16PM -0600, Jason Hoffoss wrote:


Christian
-------------- next part --------------
A non-text attachment was scrubbed…
Name: not available
Type: application/pgp-signature
Size: 186 bytes
Desc: not available
URL: http://lists.libsdl.org/pipermail/sdl-libsdl.org/attachments/20040122/add40bc5/attachment.pgp

Glenn Maynard wrote:

Huh? You realize you’re nitpicking dummy code, right?

I wasn’t especially nit-picking. It’s just that I happen to use systems
whith strict alignment rules and I often see software which works
flawlessly on Linux/x86 stumbling over it. And well for the dummy
part - excuse me - but it wasn’t me who decided to use certain
C lines instead of just “/* code for little-endian systems */”.

(Programs that really do this usually increment byte_ptr two at a time,

Even worse, he didn’t increase the pointer at all! Just kidding…

so it remains
even, but since this is only an example, that code doesn’t exist.)

Yes, it remains even if the base address was even. Often it’s not.
For example:

char buf[4096];

buf isn’t necessarily aligned on any useful boundary. That’s a real
world example and under Solaris the concerned program crashed sometimes
i.e., everytime buf (on the stack) wasn’t aligned on a 4 byte boundary
because the code used a blatant (u_int32_t *) cast on it.

There are neat compiler dependend alignment directives but you can do
something like this to enforce a certain alignment:

u_int64_t buf64[4096 / sizeof(u_int64_t)];
char *buf = (char *)&buf64

Of course, if a function requires a certain alignment for its parameters
it should use a correct prototype i.e., not just (char *).–
Christian
-------------- next part --------------
A non-text attachment was scrubbed…
Name: not available
Type: application/pgp-signature
Size: 186 bytes
Desc: not available
URL: http://lists.libsdl.org/pipermail/sdl-libsdl.org/attachments/20040122/f057ef38/attachment.pgp

Well, if you use preprocessor statements, the compiler can be as simple
as possible because it won’t even see the code which was already
thrown away by the preprocessor.

If an optimizer can’t even figure out “if(1234==1234)” at compile-time, it’s
useless. That’s a simple, fundamental optimization. I don’t believe trying
to support compilers that don’t have working optimizers is a good use of time.

#include <stdio.h>
main()
{
if( 1 == 0 )
printf(“hello world\n”);
}

01:23am glenn at zewt/3 [~] g++ foobar.cc

It’s seldom a good idea to compile C code with a C++ compiler. There are
enough corner cases where the same code has different semantics.

This is C++ code. The extension “cc” means C++. (I use C++ by default; I
consider C obsolete.)

If you really believe C and C++ will behave differently in this case,
I’m all ears; otherwise, I’m not sure what your point is. :slight_smile:

There’s no benefit of replacing all #if's withif’s. Preprocessor
directives are only bad if they tear the C code too much apart. In
that case it’s much better to write a complete function or even a
module for different cases or just restructure the code.

There’s no reason to be replacing if’s with `#if’s, either.

(I find regular if’s much easier to read.)On Thu, Jan 22, 2004 at 10:00:26PM +0100, Christian Biere wrote:


Glenn Maynard

Glenn Maynard wrote:

If an optimizer can’t even figure out “if(1234==1234)” at compile-time, it’s
useless.

Not that I knew of such a compiler but if I had a very exotic platform I’d
rather have a basic (hell, not BASIC) C compiler than none. My point was
that you can usually write something in a sane way without relying on
the implementation e.g., the proper idiom “for (;;)” vs. the infamous
"while (1)".

It’s seldom a good idea to compile C code with a C++ compiler. There are
enough corner cases where the same code has different semantics.

This is C++ code. The extension “cc” means C++. (I use C++ by default; I
consider C obsolete.)

Now, you’re nit-picking. Of course, that little piece of code isn’t a
problem. I was referring to the general case and avoiding bad examples.
If you think C is obsolete I wonder why you don’t use C++ style. Maybe
C isn’t that obsolete after all?

There’s no reason to be replacing if’s with `#if’s, either.

True that but there are things you can do with #if's you can't do withif’s - neither in C nor C++.> On Thu, Jan 22, 2004 at 10:00:26PM +0100, Christian Biere wrote:


Christian
-------------- next part --------------
A non-text attachment was scrubbed…
Name: not available
Type: application/pgp-signature
Size: 186 bytes
Desc: not available
URL: http://lists.libsdl.org/pipermail/sdl-libsdl.org/attachments/20040122/127eb673/attachment.pgp

Not that I knew of such a compiler but if I had a very exotic platform I’d
rather have a basic (hell, not BASIC) C compiler than none. My point was
that you can usually write something in a sane way without relying on
the implementation e.g., the proper idiom “for (;;)” vs. the infamous
"while (1)".

“while(1)” is much more intuitive than the ugly “for(;;)”. If a compiler
can’t figure out that “1” is always true, then (see previous comments about
useless optimizers). In fact, this is so basic that gcc 3.0 handles them
identically even with -O0.

My point is that writing sane code depends on having a sane compiler.
I don’t like to adjust my coding practices in a way that results in
harder-to-read code for the sake of not assuming that the compiler can
do basic optimizations.

Now, you’re nit-picking. Of course, that little piece of code isn’t a
problem. I was referring to the general case and avoiding bad examples.
If you think C is obsolete I wonder why you don’t use C++ style. Maybe
C isn’t that obsolete after all?

This doesn’t make any sense to me at all. The code I gave is perfectly
legitimate C++ code (except for the return type of main). C++ is a
language, not a style; this is a fact lost on some people, who don’t use
C++ for silly reasons like “I don’t like templates”.

Anyhow, this has strayed beyond SDL. If you really want to debate C vs.
C++, let’s do it in private. :)On Fri, Jan 23, 2004 at 12:20:31AM +0100, Christian Biere wrote:


Glenn Maynard

required for the platform directly instead. With the current defines in
place, you can’t have the compiler make these decisions I don’t think,
unless maybe this would work:

#if (SDL_BYTEORDER - SDL_LIL_ENDIAN)

This thread got off on a tangent without addressing the question.

You can do:

#if (SDL_BYTEORDER == SDL_LIL_ENDIAN)

If you want to force this decision to be made at preprocessor time.

–ryan.