Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > converting char to float (reading binary data from file)

Reply
Thread Tools

converting char to float (reading binary data from file)

 
 
itdevries
Guest
Posts: n/a
 
      05-21-2008
Hi,
I'm trying to convert some char data I read from a binary file (using
ifstream) to a float type. I've managed to convert the int types but
now I need to do the float types as well but it doesn't seem to work.
The code below is what I'm trying to use. Anyone see any obvious
errors? or have any hints/pointers?
regards,
Igor

float floatRead = 0;

UINT32* ptr = (UINT32 *) (&floatRead);

int offset = 0;

for (int ii=startInd; ii<=endInd; ii++){
*ptr |= (charBuf[ii] << offset);
offset += 8;
};
 
Reply With Quote
 
 
 
 
Michael DOUBEZ
Guest
Posts: n/a
 
      05-21-2008
itdevries a écrit :
> I'm trying to convert some char data I read from a binary file (using
> ifstream) to a float type. I've managed to convert the int types but
> now I need to do the float types as well but it doesn't seem to work.
> The code below is what I'm trying to use. Anyone see any obvious
> errors? or have any hints/pointers?


I suppose charBuf is of the type char[] ? In this case 'charBuf[ii] <<
offset' is 0 as soon as offset>=8 so you get only 0s.

> float floatRead = 0;
>
> UINT32* ptr = (UINT32 *) (&floatRead);
>
> int offset = 0;
>
> for (int ii=startInd; ii<=endInd; ii++){
> *ptr |= (charBuf[ii] << offset);
> offset += 8;
> };


Your use of bitwise operator looks clumsy unless you have some logic to
handle different byte ordering.

What's wrong with
memcpy(&floatRead,charBuf+startInd,sizeof(floatRea d));
?

--
Michael
 
Reply With Quote
 
 
 
 
itdevries
Guest
Posts: n/a
 
      05-21-2008
On May 21, 11:29*am, Michael DOUBEZ <(E-Mail Removed)> wrote:
> itdevries a écrit :
>
> > I'm trying to convert some char data I read from a binary file (using
> > ifstream) to a float type. I've managed to convert the int types but
> > now I need to do the float types as well but it doesn't seem to work.
> > The code below is what I'm trying to use. Anyone see any obvious
> > errors? or have any hints/pointers?

>
> I suppose charBuf is of the type char[] ? In this case 'charBuf[ii] <<
> offset' is 0 as soon as offset>=8 so you get only 0s.
>
> > float floatRead = 0;

>
> > UINT32* * *ptr *= (UINT32 *) (&floatRead);

>
> > int offset * = 0;

>
> > for (int ii=startInd; ii<=endInd; ii++){
> > * *ptr |= (charBuf[ii] << offset);
> > * offset *+= 8;
> > };

>
> Your use of bitwise operator looks clumsy unless you have some logic to
> handle different byte ordering.
>
> What's wrong with
> memcpy(&floatRead,charBuf+startInd,sizeof(floatRea d));
> ?
>
> --
> Michael


thanks, that works... however, I don't understand what's wrong with my
original code. any ideas?
Igor

 
Reply With Quote
 
Michael DOUBEZ
Guest
Posts: n/a
 
      05-21-2008
itdevries a écrit :
> On May 21, 11:29 am, Michael DOUBEZ <(E-Mail Removed)> wrote:
>> itdevries a écrit :
>>> float floatRead = 0;
>>> UINT32* ptr = (UINT32 *) (&floatRead);
>>> int offset = 0;
>>> for (int ii=startInd; ii<=endInd; ii++){
>>> *ptr |= (charBuf[ii] << offset);
>>> offset += 8;
>>> };

>
> I don't understand what's wrong with my
> original code. any ideas?


Unrolling your loop:
*ptr |= (charBuf[startInd+0] << 0);
*ptr |= (charBuf[startInd+1] << ;
*ptr |= (charBuf[startInd+2] << 16);
*ptr |= (charBuf[startInd+3] << 24);

Becomes (as I have mentionned):
*ptr |= charBuf[startInd];
*ptr |= 0;
*ptr |= 0;
*ptr |= 0;

Because you shift-left a char more times than its size in bits (usually
so it becomes 0.

Example:
char x=0xBF;
assert( (x<< == 0);
assert( (x<<12) == 0);
assert( (x<<42) == 0);

--
Michael
 
Reply With Quote
 
itdevries
Guest
Posts: n/a
 
      05-21-2008
On May 21, 12:23*pm, Michael DOUBEZ <(E-Mail Removed)> wrote:
> itdevries a écrit :
>
> > On May 21, 11:29 am, Michael DOUBEZ <(E-Mail Removed)> wrote:
> >> itdevries a écrit :
> >>> float floatRead = 0;
> >>> UINT32* * *ptr *= (UINT32 *) (&floatRead);
> >>> int offset * = 0;
> >>> for (int ii=startInd; ii<=endInd; ii++){
> >>> * *ptr |= (charBuf[ii] << offset);
> >>> * offset *+= 8;
> >>> };

>
> > I don't understand what's wrong with my
> > original code. any ideas?

>
> Unrolling your loop:
> *ptr |= (charBuf[startInd+0] << *0);
> *ptr |= (charBuf[startInd+1] << *;
> *ptr |= (charBuf[startInd+2] << 16);
> *ptr |= (charBuf[startInd+3] << 24);
>
> Becomes (as I have mentionned):
> *ptr |= charBuf[startInd];
> *ptr |= 0;
> *ptr |= 0;
> *ptr |= 0;
>
> Because you shift-left a char more times than its size in bits (usually
> so it becomes 0.
>
> Example:
> char x=0xBF;
> assert( (x<< == 0);
> assert( (x<<12) == 0);
> assert( (x<<42) == 0);
>
> --
> Michael


Thanks so much for taking the time to respond. I understand the logic
you're using and it was one of the initial concerns I had with the
code, however it seemed to work fine for int types (maybe by
coincidence) so I thought it would work for float types as well. One
thing I don't understand however is that when I step through the loop
with the debugger I see the value of the float change even though from
step 2 I thought I'd be doing "*ptr |= 0" which I thought shouldn't
alter the value of the float. that lead me to the conclusion that the
bitwise shift worked differently from what I expected.
Igor
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      05-21-2008
On 21 mai, 11:29, Michael DOUBEZ <(E-Mail Removed)> wrote:
> itdevries a écrit :
>
> > I'm trying to convert some char data I read from a binary file (using
> > ifstream) to a float type. I've managed to convert the int types but
> > now I need to do the float types as well but it doesn't seem to work.
> > The code below is what I'm trying to use. Anyone see any obvious
> > errors? or have any hints/pointers?

>
> I suppose charBuf is of the type char[] ? In this case 'charBuf[ii] <<
> offset' is 0 as soon as offset>=8 so you get only 0s.
>
> > float floatRead = 0;

>
> > UINT32* ptr = (UINT32 *) (&floatRead);

>
> > int offset = 0;

>
> > for (int ii=startInd; ii<=endInd; ii++){
> > *ptr |= (charBuf[ii] << offset);
> > offset += 8;
> > };

>
> Your use of bitwise operator looks clumsy unless you have some logic to
> handle different byte ordering.
>
> What's wrong with
> memcpy(&floatRead,charBuf+startInd,sizeof(floatRea d));
> ?
>
> --
> Michael


 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      05-21-2008
On 21 mai, 10:46, itdevries <(E-Mail Removed)> wrote:
> Hi,
> I'm trying to convert some char data I read from a binary file (using
> ifstream) to a float type. I've managed to convert the int types but
> now I need to do the float types as well but it doesn't seem to work.
> The code below is what I'm trying to use. Anyone see any obvious
> errors? or have any hints/pointers?
> regards,
> Igor
>
> float floatRead = 0;
>
> UINT32* ptr = (UINT32 *) (&floatRead);
>
> int offset = 0;
>
> for (int ii=startInd; ii<=endInd; ii++){
> *ptr |= (charBuf[ii] << offset);
> offset += 8;
>
> };


 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      05-21-2008
On 21 mai, 11:29, Michael DOUBEZ <(E-Mail Removed)> wrote:
> itdevries a écrit :


> > I'm trying to convert some char data I read from a binary
> > file (using ifstream) to a float type. I've managed to
> > convert the int types but now I need to do the float types
> > as well but it doesn't seem to work. The code below is what
> > I'm trying to use. Anyone see any obvious errors? or have
> > any hints/pointers?


> I suppose charBuf is of the type char[] ? In this case
> 'charBuf[ii] << offset' is 0 as soon as offset>=8 so you get
> only 0s.


Since when? That's not what my compiler does, and it's not what
the standard requires. In expressions, char's are promoted to
int's.

> > float floatRead = 0;


> > UINT32* ptr = (UINT32 *) (&floatRead);


> > int offset = 0;


> > for (int ii=startInd; ii<=endInd; ii++){
> > *ptr |= (charBuf[ii] << offset);
> > offset += 8;
> > };


Without seeing the other declarations, it's hard to say. What
is charBuf? Normally, I'd expect it to be an unsigned char*,
otherwise, the integral promotion of charBuf[ii] will extend the
sign, which will definitely not give you the results you want.
(If it's char*, you can always mask out the unwanted bits from
the extension, i.e.:
((charBuf[ ii ] & 0xFF) << offset)
You don't show startInd and endInd either. Obviously, they make
a difference.

When all is said and done, I'd unwind the loop:

*ptr = ((charBuf[ 0 ] & 0xFF) ) ;
*ptr |= ((charBuf[ 0 ] & 0xFF) << ;
*ptr |= ((charBuf[ 0 ] & 0xFF) << 16) ;
*ptr |= ((charBuf[ 0 ] & 0xFF) << 24) ;

Note that you are also assuming that the representation of the
that you are reading more or less corresponds to the internal
representation on your machine (modulo byte order). This isn't
really something you can portably count on. (On the other hand,
doing it really right, in a 100% portable fashion, is relatively
difficult. I'd probably put in some sort of #if and and #error
to catch the case, and only add the complexity if the need
arose.)

> Your use of bitwise operator looks clumsy unless you have some
> logic to handle different byte ordering.


> What's wrong with
> memcpy(&floatRead,charBuf+startInd,sizeof(floatRea d));
> ?


Maybe the fact that it doesn't have the correct semantics? (It
might work, sometimes, but it's certainly a risky procedure.)

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
Michael DOUBEZ
Guest
Posts: n/a
 
      05-21-2008
James Kanze a écrit :
> On 21 mai, 11:29, Michael DOUBEZ <(E-Mail Removed)> wrote:
>> itdevries a écrit :

>
>>> I'm trying to convert some char data I read from a binary
>>> file (using ifstream) to a float type. I've managed to
>>> convert the int types but now I need to do the float types
>>> as well but it doesn't seem to work. The code below is what
>>> I'm trying to use. Anyone see any obvious errors? or have
>>> any hints/pointers?

>
>> I suppose charBuf is of the type char[] ? In this case
>> 'charBuf[ii] << offset' is 0 as soon as offset>=8 so you get
>> only 0s.

>
> Since when? That's not what my compiler does, and it's not what
> the standard requires. In expressions, char's are promoted to
> int's.


Then, it is my mistake and I am the worse for not checking.
I am always careful to avoid writing code like that.

>> What's wrong with
>> memcpy(&floatRead,charBuf+startInd,sizeof(floatRea d));
>> ?

>
> Maybe the fact that it doesn't have the correct semantics? (It
> might work, sometimes, but it's certainly a risky procedure.


More risky than using bitwise operators to build a float ?

Concerning the semantic, I don't see what could be a correct one in this
case since reading a binary flow to build a float is however heretical;
unless you have some kind of standard transform and assuming the
capacities of representation are equivalent across addressed architectures.

What is uncorrect with dumping the memory area representing a POD and
reading it back in the same program ?


--
Michael
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      05-22-2008
On May 21, 10:49 pm, Michael DOUBEZ <(E-Mail Removed)> wrote:
> James Kanze a écrit :
> > On 21 mai, 11:29, Michael DOUBEZ <(E-Mail Removed)> wrote:
> >> itdevries a écrit :


> >>> I'm trying to convert some char data I read from a binary
> >>> file (using ifstream) to a float type. I've managed to
> >>> convert the int types but now I need to do the float types
> >>> as well but it doesn't seem to work. The code below is what
> >>> I'm trying to use. Anyone see any obvious errors? or have
> >>> any hints/pointers?


> >> I suppose charBuf is of the type char[] ? In this case
> >> 'charBuf[ii] << offset' is 0 as soon as offset>=8 so you get
> >> only 0s.


> > Since when? That's not what my compiler does, and it's not
> > what the standard requires. In expressions, char's are
> > promoted to int's.


> Then, it is my mistake and I am the worse for not checking. I
> am always careful to avoid writing code like that.


> >> What's wrong with
> >> memcpy(&floatRead,charBuf+startInd,sizeof(floatRea d));
> >> ?


> > Maybe the fact that it doesn't have the correct semantics? (It
> > might work, sometimes, but it's certainly a risky procedure.


> More risky than using bitwise operators to build a float ?


Yes.

Basically, using the bitwise operators depends on the external
representation being the same as the internal, i.e. they are
both IEEE (or both something else, but I've never seen that
case). In practice, a lot of modern protocols do use IEEE, and
most modern small and medium sized computers also use it
internally, so if you are only targetting Windows and mainstream
Unix, you're safe (and a few judicious #if on the values defined
in <climits>, controlling an #error, can assure that it probably
won't compile on systems which don't use IEEE).

It's ugly, but the alternative is a lot more complex.
(Interestingly, it's not that much slower on my machine. Which
rather surprised me.)

> Concerning the semantic, I don't see what could be a correct
> one in this case since reading a binary flow to build a float
> is however heretical; unless you have some kind of standard
> transform and assuming the capacities of representation are
> equivalent across addressed architectures.


As mentionned above, a lot of protocols (BER being the only
exception which comes to mind) use IEEE format for floating
point, as do a lot of machines. In this case, reading the value
as if it were the same sized unsigned integer type (uint32_t or
uint64_t, depending on whether you're reading float or double),
followed by some sort of nasty cast, will work.

> What is uncorrect with dumping the memory area representing a
> POD and reading it back in the same program ?


The fact that there are still significant differences in the
binary representation, particularly with regards to byte order.
If you want to be really correctly, you need something like:

uint32_t tmp ;
operator>>( tmp ) ;
if ( *this ) {
float f = 0.0 ;
if ( (tmp & 0x7FFFFFFF) != 0 ) {
f = ldexp( ((tmp & 0x007FFFFF) | 0x00800000),
(int)((tmp & 0x7F800000) >> 23) - 126 - 24 ) ;
}
if ( (tmp & 0x80000000) != 0 ) {
f = -f ;
}
dest = f ;
}
return *this ;

You still read the type into the unsigned int (using shifts),
but then you extract the fields as they are specified in the
format, and use them to create a float, using standard functions
to exploit their values in a portable fashion. As I've said
previously, this is probably more work than necessary, and until
needed, I'd just go with the ugly cast (and the #if/#error, to
ensure that it doesn't get used when not appropriate).

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
reading binary file into memory. Converting from char to uint32,float, double, ASCII strings etc (static_cast< > ?) someone C++ 37 10-18-2011 01:32 AM
float to string to float, with first float == second float Carsten Fuchs C++ 45 10-08-2009 09:47 AM
(const char *cp) and (char *p) are consistent type, (const char **cpp) and (char **pp) are not consistent lovecreatesbeauty C Programming 1 05-09-2006 08:01 AM
/usr/bin/ld: ../../dist/lib/libjsdombase_s.a(BlockGrouper.o)(.text+0x98): unresolvable relocation against symbol `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostre silverburgh.meryl@gmail.com C++ 3 03-09-2006 12:14 AM
Re: float->byte->float is same with original float image. why float->ubyte->float is different??? bd C Programming 0 07-07-2003 12:09 AM



Advertisments