Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

Why this binary file code is not working>

Posted on 2003-03-30
15
Medium Priority
?
320 Views
Last Modified: 2012-05-05
void main
{
     struct ibm
     {
          char startbit;
          float salary;
          char name[10];
          char stopbit;
     };

     ibm ibm1 = {'t',885.34,"abcdefghi",'f'};
     
     fstream File("c:\\sample.bin", ios::out |  ios::in | ios::binary);
        File.write((char *)(&ibm1), sizeof(ibm));

        float readreal = 0.0;
     File.seekg(sizeof(char) ,ios::beg);
     File.read((char*)&readreal,sizeof(float));
     cout << "Float value with byte addition\t" << readreal;
}
I'm not getting the value 885.34 printed. Why?
I've few more questions, but let's see this one first.
0
Comment
Question by:Francoz
  • 5
  • 5
  • 2
  • +2
15 Comments
 
LVL 2

Expert Comment

by:Aleph
ID: 8236993
try:
cout << "Float value with byte addition\t" << readreal << endl;
0
 
LVL 2

Expert Comment

by:Aleph
ID: 8237017
By the way, that struct is probably not packed. On most computers, 4-byte values must be aligned to addresses that are a multiple of 4, and since the whole struct probably is aligned in such a way, 3 bytes of padding will be inserted after the first char.
0
 
LVL 8

Expert Comment

by:fl0yd
ID: 8237056
As a side note, this isn't a valid c++ program to start with. The application entry point isn't defined and your linker should complain about this. Use this function signature instead:

int main( int argc, char* argv[] )

Apart from that, Aleph hit the nail. I would also think that it is an alignmet issue. To check this, calculate sizeof( ibm ) and compare it to sizeof( char ) + sizeof( float ) + sizeof( char[10] ) + sizeof( char ). Those 2 values are likely not the same.

.f
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
LVL 30

Expert Comment

by:Mayank S
ID: 8237269
Well, there are often many unexpected issues involved with the storage of floating-point variables. I once happened to try the folowing code:

float a = 0.6 ;

if ( a < 0.6 )
  cout << "\n Lesser. " ; // end if
 
else
   cout << "\n Greater or equal. " ; // end else

a = 0.7 ;

if ( a < 0.7 )
  cout << "\n Lesser. " ; // end if
 
else
  cout << "\n Greater or equal. " ; // end else


And the output I got was:

Greater or equal.
Lesser.


There is often a loss of precision in storing floating-point values, which is why I never use them now. I always prefer using 'double'. In fact, even in the above code, when I changed the data-type of 'a' to 'double', the output was:

Greater or equal.
Greater or equal.

And on another testing, after writing 35.67 (stored in a floating-point variable) to a file, when I read it, I got 35.668294! I changed the data-type to 'double', and my problem was solved.

Just thought I'll let you know.... might be of some help to you.

Mayank.

PS:
>> float readreal = 0.0;
>> File.seekg(sizeof(char) ,ios::beg);
>> File.read((char*)&readreal,sizeof(float));
>> cout << "Float value with byte addition\t" << readreal;

Try using a structure variable to read it:

ibm temp ;
File.seekg ( 0, ios :: beg ) ;
File.read ( ( char * ) &temp, sizeof ( ibm ) ) ;

There are few other errors with your code too (like the missing parethesis () after 'main', etc) but I guess you must've corrected them by now.

Mayank.
0
 
LVL 1

Accepted Solution

by:
TriG earned 60 total points
ID: 8237353

ibm ibm1 = {'t',885.34,"abcdefghi",'f'};

This assignment is fine... regardless of alignment.  Note that there is an implicit cast from double to float (the literal 885.34 is a double if you don't put an f afterwards)  Anyways, that's OK too.


But as  mayankeagle has shown, the reading code is wrong cuz of the packing.  On a PC using vc++ the char will take up 4 bytes (3 bytes of padding).

so
File.seekg(sizeof(char) ,ios::beg);

should read
File.seekg(4 ,ios::beg);

Usually you can give hints to the compiler as to how to pack.  See docs for

#pragma pack... and
__declspec(align(#))


Also, beware that the file generated is not necessarily portable to other platforms as the endianness (the order of bytes that represent numbers) may be different.
0
 
LVL 2

Author Comment

by:Francoz
ID: 8237436
Actually I wanted result why the seekg() func is not able to give me the correct location of pointer. I feel Trig has answered correctly. I made change to the func as follows

File.seekg(sizeof(char)+3 ,ios::beg);
//The size 3 is added for padding

Now it works correctly. And also to eliminate the warning we can give floating point assignment as

real = 0.0F;

Hey trig can you tell me something more on padding.
One interesting result is if I give float as the first element of struct the file size is 16bytes. Otherwise it is 20bytes.
0
 
LVL 2

Expert Comment

by:Aleph
ID: 8237695
> One interesting result is if I give float as the first element of struct the file size is 16bytes. Otherwise it is 20bytes.

That is because, as I said before, the float, which is a four byte field, must be stored at an address in the memory that is an even multiple of four. Since your whole struct is stored at such a location, that is fine when the float is the first field in the struct. But when you have a char as the first field, three bytes of padding is inserted by the compiler in order to align the float to a valid address.

0x1230 | char | pad  | pad  | pad  |
0x1234 |          float            |
0x1238 | char | char | char | char |
...

makes it 20 bytes, wheras

0x1230 |          float            |
0x1234 | char | char | char | char |
0x1238 | char | char | char | char |
...

makes it 16 bytes
0
 
LVL 1

Expert Comment

by:TriG
ID: 8238362
That's it.

These alignment issues are for improved efficiency only.  Non aligned floats etc must work... but on older processors they might run slower (there's barely a difference with, say, a new P4)

i.e.  This should work fine ( assuming the new returned a 4 byte aligned mem location... which it will always do, but isn't required to).

   ibm ibm1 = {'t',885.34f,"abcdefghi",'f'};
   char* space = new char[ sizeof(ibm) + 1 ];
   ibm* pIBM = (ibm*)(space+1);
   *pIBM = ibm1;

   fstream File("c:\\sample.bin", ios::out |  ios::in | ios::binary);
   File.write((char *)(pIBM), sizeof(ibm));

So should multiplying unaligned floats etc.  Some assembly instructions require alignment (eg. SSE instructions) and can be capitalized on if things are tidy.  That's not to say alignment isn't required in all sorts of cases (DMA's, ethernet drivers, etc., etc.) but we're only dealing with the language, not an API.

--tri
0
 
LVL 8

Expert Comment

by:fl0yd
ID: 8238414
TriG: "there's barely a difference with, say, a new P4"

Erm, why shouldn't it be a problem there? It most definately is more of a problem on newer cpu's than on those old ones, where memory access bottlenecks weren't that much of a hassle, due to the simple design of the MCH. Sure, if your cpu runs on 2GHz it will feel like there isn't a problem when comparing it to a 386 33MHz -- it is, however, in relation a lot more of a penalty.

.f
0
 
LVL 2

Expert Comment

by:Aleph
ID: 8238528
> These alignment issues are for improved efficiency only.

Not really. Many processors require that types are aligned in order to work with them. If you try to access a field that isn't aligned you'll get a bus error. I'm not sure about the specifics of the x86 architecture -- perhaps it can handle unaligned fields since it's a CISC processor -- but for example a Sun SPARC processor can't.

You can however instruct the compiler to pack structures, but that only means it will produce extra code to work around the problem, unless I'm mistaken.
0
 
LVL 2

Author Comment

by:Francoz
ID: 8238931
Hi everyone I feel the main qn is answered now. thanx trig,aleph,mayankeagle  and all.
0
 
LVL 1

Expert Comment

by:TriG
ID: 8241344
>These alignment issues are for improved efficiency only.

I should have emphasized the word "These" more.  Yes, there are many cases where alignment is required, but a language abstracts those details... That's why ANSI C, for example, doesn't guarantee anything about how things get packed in a struct; it needs freedom to accomodate the hardware.

The unaligned code I submitted must work, even on a SPARC... as you said, the compiler may have to produce more code to work around the problem, thus making it less efficient.

--tri
0
 
LVL 1

Expert Comment

by:TriG
ID: 8241647
fl0yd,

>"there's barely a difference with, say, a new P4"

Yeah, I shouldn't have said that.  Alignment is very important for efficiency.

I've been doing math code using SIMD instructions and was noticing how the latencies for the unaligned versus aligned stores and loads are near identical.

MOVAPS Load->4  Store->4
MOVUPS Load->4  Store->5

but I shouldn't have implied that, in general, it doesn't matter much.

--tri
0
 
LVL 2

Expert Comment

by:Aleph
ID: 8253498
TriG,

No, it won't work. Running this on a SunBlade 100:

  struct S { Float f; };
  S s;
  s.f = 0.0;
  char *space = new char[sizeof(S) + 1];
  S* sp = (S*) (space + 1);
  *sp = s; // Error here

gives this error:

  Bus Error

Bucause *sp cannot be dereferenced as a four byte type while not aligned.
0
 
LVL 1

Expert Comment

by:TriG
ID: 8257577
Hmm,

Well, there are two ways to go here :)

A) Either admit that the code shouldn't be portable, or

B) Claim that your SunBlade 100 should have implemented chars as 32bits each if it can't deal with the lack of aligment.

Note: sizeof(char) should equal to 1 even on a 4byte per character machine... which, according to the God Stoustrup 3rd edition p76, do in fact exist.

I suppose the question is, did the compiler on the Sun opt not to support the Language exactly, which, if the language requires the above to work, is the only reasonable thing to do (who would want 4byte characters?)

OR

Does C++ to allow the above to be considered non-portable?

Still holding on by a thread :)

--tri


0

Featured Post

Receive 1:1 tech help

Solve your biggest tech problems alongside global tech experts with 1:1 help.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

569 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question