Is this the correct?!

C

Chris Croughton

As far as why determining the endianness may be important, I often
write code to communicate among devices via SPI on devices where the
transmit buffer is 8 bits. Since I have to send data as a stream of
bytes, endianness becomes important. All the existing code assumes big
endian micros. We only use 2's complement implementations but I don't
see why we might not switch to a little-endian architecture.

The portable way to do it is to decide in your protocol which way round
things are going to be passed ("network byte order" as used in TCP/IP is
defined by the standards for that protocol as MSB first, for instance)
and convert the data using C arithmetic operators:

void put8bit(unsigned char v);

void put16(unsigned short v)
{
put8(v >> 8);
put8(v);
}

void put32(unsigned long v)
{
put16(v >> 16);
put16(v);
}

unsigned char get8(void);

unsigned short get16(void)
{
unsigned short v = (unsigned short)get8() << 8;
return v + get8();
}

unsigned long get32(void)
{
unsigned long v = (unsigned long)get16() << 8;
return v + get16();
}

I've used unsigned short and unsigned long because the former is
guaranteed to be at least 16 bits and the latter guaranteed to be at
least 32 bits. If you have stdint.h on your sustem you can use the
appropriate sized types.

The functions are illustrative, and I've deliberately left the 8 bit put
and get functions undefined, additional parameters can be added, there's
no error checking, etc. The point is that the routies are totally
agnostic of the underlying representations on the target machine and are
thus fully portable.

putX() and getX() can easily be defined for structures in that way.

If you want to pass signed data, you will need to build into the
protocol a portable method of doing it, since not all processors are 2-s
complement (although in practice you may be able to assume that for your
system). Something like:

void puts32(long v)
{
if (v < 0)
{
/* possibly handle LONG_MIN == 0x80000000 case */
put32(0x80000000 | -v);
}
else
put32(v);
}

long gets32(void)
{
unsigned long v = get32();
if (v & 0x80000000)
return -(long)(v & 0x7FFFFFFF);
else
return (long)v;
}

Or something like that.

In regard to your point about embedded systems in general needing to
know what endianness they are, in almost all cases[1] this can be
determined by the system builder before compilation and set a define to
flag which is being used:

#ifdef MSB_FIRST
/* do little-endian stuff */
#else
/* do big-endian stuff */
#endif

Anything like that should be restricted to a small part of the program,
so that if you need to cope with something like the PDP-11
bastard-endian (3412 or something like that) you can easily add extra
code to do it.

An alternative way of doing it is to provide macros or functions,
contitionally compiled to get the right ones, which do the conversions.
Look at the POSIX ntohl and ntohs macros, for example.

Chris C
 
J

joshc

Chris said:
In that case, do it yourself, so that you have control:

This code works if your machine is little-endian, big-endian,
PDP-endian, or even My-Favorite-Martian-antenna-endian. It works
if your "char"s are 8 bits, or 9 bits, or 16 bits, or 32 bits
(provided send_SPI_data() can somehow manage to send the low 8 bits
of each "unsigned char" out to the appropriate device).

In short, it always works.

Cool! Thanks to Chris Torek and CBFalconer. I've only been trying to
write standard C for about 6 months so at times it becomes difficult
for me to distinguish what is portable and what isn't since I work in
the embedded realm. I'm a bit embarassed to say that I recently
graduated from one of the top 5 computer science schools but no
emphasis was really placed on the Standard. We used K&R as a reference,
but as long as it all ran on the particular implementation in the
computer labs, that's all that mattered.

Thanks again!
 
C

CBFalconer

joshc said:
Cool! Thanks to Chris Torek and CBFalconer. I've only been trying to
write standard C for about 6 months so at times it becomes difficult
for me to distinguish what is portable and what isn't since I work
in the embedded realm. I'm a bit embarassed to say that I recently
graduated from one of the top 5 computer science schools but no
emphasis was really placed on the Standard. We used K&R as a
reference, but as long as it all ran on the particular
implementation in the computer labs, that's all that mattered.

You are welcome. This is a refreshing attitude after all the types
who come back with an argument and 'it works on my machine'.

Look around on <http://www.open-std.org/jtc1/sc22/wg14/www/docs/>
for n1124 (3.5 MB) and n869 (1.1 to 1.5 MB) which are free drafts
of the upcoming C05 and past C99 standards. For n869 you can get a
text version, which is searchable with grep and similar tools. On
my site <http://cbfalconer.home.att.net/download> you can find a
slightly edited version (for searching and quoting) in n869_txt.bz2
(212 KB).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,166
Messages
2,570,903
Members
47,444
Latest member
Michaeltoyler01

Latest Threads

Top