Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Message

Re: For C novices

2006-03-31 by garycordelli

Yes, indeed.

In fact, portable communications code often includes functions (or
macro equivalents) that -- assuming the external comms is, like TCP,
undertaken in big-endian byte order -- look like (written here for
clarity, not efficiency):

int32 ExtractInt32(char *p)
{
    int32 value;

    // (note: mask bits to ignore sign-extend on bytes >= 0x80)
#ifdef BIGENDIAN_CPU  
    // extract bytes to big-endian storage (matches buffer order)
    value = p[0]; // skip mask, since sign-extend bits will shift off
    value = (value << 8) | (p[1] & 0x00FF);
    value = (value << 8) | (p[2] & 0x00FF);
    value = (value << 8) | (p[3] & 0x00FF);
#else  
    // extract bytes to little-endian storage (opposite buffer order)
    value = p[3]; // skip mask, since sign-extend bits will shift off
    value = (value << 8) | (p[2] & 0x00FF);
    value = (value << 8) | (p[1] & 0x00FF);
    value = (value << 8) | (p[0] & 0x00FF);
#endif
    return value;
}

void InsertInt32(int32 value, char *p)
{
    // (note: conversion is done implicitly, but cast avoids warning)
#ifdef BIGENDIAN_CPU  
    // assign bytes from big-endian mutli-byte storage type
    p[0] = (char)(value >> 24);
    p[1] = (char)(value >> 16);
    p[2] = (char)(value >> 8);
    p[3] = (char)value;
#else  
    // assign bytes from little-endian multi-byte storage type
    p[0] = (char)value;
    p[1] = (char)(value >> 8);
    p[2] = (char)(value >> 16);
    p[3] = (char)(value >> 24);
#endif
}

Then "int32 value = ExtractInt32(p);" can be used to extract 32-bit
integers from the communications buffer on receipt and
"InsertInt32(value, p);" can be used to insert 32-bit integers into
the communications buffer for transmit -- all regardless of alignment
of these fields within the "char buffer[]", and can also automatically
handle differences in the "endianess" of the external communications
byte ordering and the internal CPU byte ordering (just #define/#undef
BIGENDIAN according to what target processor you are compiling for).

Then your internal data structures don't have to care if the message
structures are "compatible" with the processor you are porting to.  It
is ugly and a tad inefficient, but that's the price you pay for
portability.

The above operations are not, despite your strongest desire, the job
of the compiler, but the programmer.

Cordeg


--- In lpc2000@yahoogroups.com, Robert Adsett <subscriptions@...> wrote:
>
> Quoting Clyde Stubbs <clyde@...>:
> 
> > On Fri, Mar 31, 2006 at 02:20:12AM -0000, garycordelli wrote:
> >> Just a postscript: this is not an academic notion to which I allude,
> >> but a common error in just the kind of code I am paid to fix
every day.
> >>
> >> The circumstances tend to be communications code, where the
programmer
> >> has created a generic n-byte buffer:
> >
> <snip>
> > The bottom line - if you want to *portably* encode/decode
bytestreams of this
> > nature you have to do it one byte at a time. There is no other way
to ensure
> > that the same code will work across different architectures.
> 
> Amen.  Do it right, save yourself future headaches.  Separate the 
> communications
> format from the internal structure. Even if they happen to match.
> 
> > Wanna encode a
> > 16 bit value as two sequential bytes? Do it like this:
> >
> > 	*cp++ = (val & 0xFF);
> > 	*cp++ = (val >> 8) & 0xFF;
> >
> > The masking is redundant, but makes it clear what you're doing,
and will be
> > optimized away by any decent compiler.
> 
> The harder part is going the other way and making sure things get sign 
> extended
> properly, especially if communication size and internal storage size
don't
> match.
> 
> As a for instance I've seen CAN protocols that use a 10bit signed
int 'across
> the wire'
> 
> > Now if you happen to have code that someone naively wrote that
only works
> > on one particular architecture - don't expect a compiler to save
you. Just
> > bite the bullet, rewrite the code properly, and learn from the
experience.
> > It will save you a LOT of time in the long run.
> 
> And get yourself a good lint, theres a good chance there are more 
> gotchas hidden
> in the code.
> 
> Robert
>

Attachments

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.