Topic: Standard way for coverting byte stream to a signed two's complement number


Author: Sebastian Redl <e0226430@student.tuwien.ac.at>
Date: Mon, 19 Nov 2007 09:50:23 CST
Raw View
petek1976 wrote:

> unsigned long ExtractUInt32M(const unsigned char *apnOctets)
> {
>   const unsigned char *lpnOctets = apnOctets;
>   unsigned long lnValue = *(lpnOctets++);
>   lnValue = (lnValue << 8) | *(lpnOctets++);
>   lnValue = (lnValue << 8) | *(lpnOctets++);
>   lnValue = (lnValue << 8) | *(lpnOctets);
>   return lnValue;
>  }

1) unsigned char isn't guaranteed to be 8 bits large.
2) unsigned long isn't guaranteed to be 32 bits large.

Of the two, the latter is the realistic issue. GCC in 64-bit mode has a
64-bit long. char is 8 bits on pretty much every platform, except for some
embedded systems that only support word addressing and have 16- or 32-bit
chars.

> In line 8 the process is completed by subtracting 2^31 again,
> which will result in the correct negative value.

There is no guarantee that numbers use 2's complement either. (Again, more
of a theoretical issue.)

For all of their closeness to the system, you still have to rely on
platform-specific behaviour when you fiddle with raw binary data in C++.
That may be deliberate - fiddling with bytes *is* platform-specific, after
all.

--
Sebastian Redl

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: petek1976 <pete.karousos@earthlink.net>
Date: Mon, 12 Nov 2007 08:45:12 CST
Raw View
Hi,

The C++ standard does not appear to guarantee any representation for
signed integers. So if I were defining an interface that expected a
sequence of bytes in big-endian byte order (no matter what the
architecture/platform) and I wanted to convert a sequence of unsigned
char* to a signed number do I really have to do this:

unsigned long ExtractUInt32M(const unsigned char *apnOctets)
{
  const unsigned char *lpnOctets = apnOctets;
  unsigned long lnValue = *(lpnOctets++);
  lnValue = (lnValue << 8) | *(lpnOctets++);
  lnValue = (lnValue << 8) | *(lpnOctets++);
  lnValue = (lnValue << 8) | *(lpnOctets);
  return lnValue;
 }

long ExtractSInt32M(const unsigned char *apnOctets)
{
 unsigned long lnBaseBits = ExtractUInt32M(apnOctets); // treat as
unsigned first
 long lnValue;
 if ((lnBaseBits & 0x80000000) != 0) // Check for negative value
 {
 lnValue = lnBaseBits - 2147483648; // line 7
 lnValue -= 2147483648; // line 8
 }
else
{
   lnValue = lnBaseBits;
}
return lnValue;
}

Notice the lines that subtract 2^31. This is all based on the fact
that a negative number in twos complement is represented as 2^N -
abs(value). First 2^32 (4294967296) is beyond the guaranteed range for
either a long or an unsigned long in C++. Second the C++ language does
not define what happens if you convert an out of range value long (or
any other integer type). In our case if the two's complement number
represents a negative value, it is undefined what will happen if I
were to assign lnBaseBits directly to lnValue. I solve both of these
issues by
performing the subtraction in two steps. 2^31 is subtracted from
lnBaseBits. Since that is a positive value which is guaranteed to be
within the range of a long, I can safely assign that result to
lnValue. In line 8 the process is completed by subtracting 2^31 again,
which will result in the correct negative value. Of course what I am
doing here is still not really portable since the standard only
guarantees a long value of 2147483647. Isn't there an easier way that
does not violate the C++ standard and stil be portable? Will the next
revision of the standard make such a task easier by doing something
like guaranteeing the representation of a signed number so that bit-
shifting will result in sign-extension?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]