# [Newbie] Once more on conversions

Discussion in 'C++' started by Barzo, Jan 27, 2009.

1. ### BarzoGuest

Hi,

I'm sorry if my questions are banal...
I have to this 'simple' work:

INPUT: std::string buffer = [11][8E][CD][8D] --> <<CONVERSION>> -->
OUTPUT: std::string = "12,345345"

The buffer arrives from a device that use big-endian.

[11][8E][CD][8D] = 294571405

(294571405 * 90) / 0x80000000 = 12,34534496907....

My routine is (after have readed some posts here..) but it doen't
work:

template< typename T >
std::string ToString( const T& val )
{
try
{
return boost::lexical_cast<std::string>(val);
}
{
// std::cout << e.what();
return 0;
}
}

template<class T>
void fromBytes(unsigned char const* bytes, T* t)
{
*t = 0;
for(int i = 0; i != sizeof t; ++i)
*t |= bytes << 8 * i;
}

float decode_lat(const std::string& buffer, char token_pos)
{
// VAL = ((L * (2^31))/90) => L = ((VAL * 90)/(2^31))
// (2^31)=0x80000000

float lat = 0;
unsigned long val = 0;

// Extract the 4 latitude octets from the buffer and
// convert they into an long value
fromBytes<unsigned long>(reinterpret_cast<const unsigned char*>
(buffer.substr(token_pos, 4).c_str()), &val);

if (val == 0x7FFFFFFF)
lat = 90;
else
lat = ((unsigned long)(val * 90) / 0x80000000);

// The MSBit indicates the sign
return ( ((buffer[token_pos] & 0x80) == 0x80) ? -lat : lat );
}

void CallerFunction()
{...
std::string s = ToString<float>( decode_lat(buffer, token_pos) );
}

Could someone explain me what is wrong in this code?
Is this code portable? If not, is there a method to accomplish this?

Daniele.

Barzo, Jan 27, 2009

2. ### Michael DOUBEZGuest

Barzo wrote:
> Hi,
>
> I'm sorry if my questions are banal...
> I have to this 'simple' work:
>
> INPUT: std::string buffer = [11][8E][CD][8D] --> <<CONVERSION>> -->
> OUTPUT: std::string = "12,345345"
>
> The buffer arrives from a device that use big-endian.
>
> [11][8E][CD][8D] = 294571405
>
> (294571405 * 90) / 0x80000000 = 12,34534496907....
>
> My routine is (after have readed some posts here..) but it doen't
> work:
>
> template< typename T >
> std::string ToString( const T& val )
> {
> try
> {
> return boost::lexical_cast<std::string>(val);
> }
> {
> // std::cout << e.what();
> return 0;

Here you return a string with NULL as parameter.
This is a candidate for segfault.

Perhaps you where thinking of:
return "0";

> }
> }
>
> template<class T>
> void fromBytes(unsigned char const* bytes, T* t)
> {
> *t = 0;
> for(int i = 0; i != sizeof t; ++i)
> *t |= bytes << 8 * i;
> }
>
> float decode_lat(const std::string& buffer, char token_pos)
> {
> // VAL = ((L * (2^31))/90) => L = ((VAL * 90)/(2^31))
> // (2^31)=0x80000000
>
> float lat = 0;
> unsigned long val = 0;
>
> // Extract the 4 latitude octets from the buffer and
> // convert they into an long value
> fromBytes<unsigned long>(reinterpret_cast<const unsigned char*>
> (buffer.substr(token_pos, 4).c_str()), &val);
>
> if (val == 0x7FFFFFFF)
> lat = 90;
> else
> lat = ((unsigned long)(val * 90) / 0x80000000);

perhaps could you consider modifying your expression to:
lat = unsigned long( val * (90.0/0x80000000) ) );

It would save you possible overflow.

>
> // The MSBit indicates the sign
> return ( ((buffer[token_pos] & 0x80) == 0x80) ? -lat : lat );
> }
>
> void CallerFunction()
> {...
> std::string s = ToString<float>( decode_lat(buffer, token_pos) );
> }
>
> Could someone explain me what is wrong in this code?
> Is this code portable? If not, is there a method to accomplish this?

What doesn't work ?

--
Michael

Michael DOUBEZ, Jan 27, 2009

3. ### Thomas J. GritzanGuest

Victor Bazarov wrote:
> Barzo wrote:
>> I'm sorry if my questions are banal...
>> I have to this 'simple' work:
>>
>> INPUT: std::string buffer = [11][8E][CD][8D] --> <<CONVERSION>> -->
>> OUTPUT: std::string = "12,345345"
>>
>> The buffer arrives from a device that use big-endian.

Big-endian, so 0x8D goes into bit 7 to bit 0 (with bit 0 = LSB).

>> [11][8E][CD][8D] = 294571405

[...]
>> template<class T>
>> void fromBytes(unsigned char const* bytes, T* t)
>> {
>> *t = 0;
>> for(int i = 0; i != sizeof t; ++i)
>> *t |= bytes << 8 * i;
>> }

0x8D is read in the 4th loop cycle, so
*t |= 0x8D << 8 * 3;
is executed. 0x8D is stored at bit 31 to bit 24.

Conclusion: This function reads from little-endian and doesn't do what
you want.

>> float decode_lat(const std::string& buffer, char token_pos)
>> {
>> // VAL = ((L * (2^31))/90) => L = ((VAL * 90)/(2^31))
>> // (2^31)=0x80000000
>>
>> float lat = 0;
>> unsigned long val = 0;
>>
>> // Extract the 4 latitude octets from the buffer and
>> // convert they into an long value
>> fromBytes<unsigned long>(reinterpret_cast<const unsigned char*>
>> (buffer.substr(token_pos, 4).c_str()), &val);

The explicit template argument is not needed, since the type is deduced
from the second parameter.
The substr() call constructs a temporary string and is also not needed.

fromBytes(reinterpret_cast<const unsigned char*>(buffer.c_str() +
token_pos, &val);

However, you should check if buffer is large enough.

[...]
>> // The MSBit indicates the sign
>> return ( ((buffer[token_pos] & 0x80) == 0x80) ? -lat : lat );

You might have to set the sign bit to 0 in val before the conversion:

float lat = (val & 0x7FFFFFFF) * (90.0 / 1<<31);

Then negate lat if the sign bit is set.

--
Thomas

Thomas J. Gritzan, Jan 27, 2009