[Newbie] Once more on conversions


B

Barzo

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);
}
catch(const boost::bad_lexical_cast& e)
{
// 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?

Tnx in advance!
Daniele.
 
Ad

Advertisements

M

Michael DOUBEZ

Barzo said:
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);
}
catch(const boost::bad_lexical_cast& e)
{
// 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 ?
 
Ad

Advertisements

T

Thomas J. Gritzan

Victor said:
Barzo said:
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.

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.
 

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

Top