Date: Fri, 23 Feb 2001 07:38:42 +0000
From: Olav Beckmann
To: JimStanton
Subject: Re: Reinterpret cast in Linux
Hi again,
I have read the section in the C standard Book that talks about
bitfields, and I think what you are doing ought to work.
Just one other thought:
What about
typedef union {
long l_number;
struct {
unsigned int b0 : 8;
unsigned int b1 : 8;
unsigned int b2 : 8;
unsigned int b3 : 8;
} bytes;
} fourbyte;
Then
fourbyte fb;
in.get(ch); fb.bytes.b0 = ch;
[...]
Then use it as
fb.l_number
The meaning of a union is that you can interpret the same area of memory
in different ways - here we would be interpreting it as 4 8-bit chars
(via fb.bytes) and as a long.
But if it works at present, you should leave it.
Olav
JimStanton wrote:
>
> Hello Olaf,
>
> Thank you for this message and for your comments.
> The structure definition I am using is as follows:
>
> struct FOURBYTE {
> unsigned char byte0 : 8;
> unsigned char byte1 : 8;
> unsigned char byte2 : 8;
> unsigned char byte3 : 8;
> };
>
> and use of the bitfield construct I think makes it function
> correctly (it has consistently given the correct answer on
> both Visual C++ and g++, both on debug builds and release
> builds - optimization flag -O3 on g++). Do you still think
> that this is suspect?
>
> I went through a number of other possible techniques early in
> the term before concluding from the book "Navigating C++"
> that this approach was necessary. I've just rechecked if it is
> possible to use read and the following does seem to work
> (it should read the height as an unsigned long starting at byte 22) :
>
> #include <iostream.h>
> #include <fstream.h>
>
> int main()
> {
> unsigned long height;
> ifstream in;
> in.open("monalisa.bmp", ios::binary);
>
> in.seekg(22);
> in.read((char*)&height,4);
>
> cout << height << endl;
>
> return 0;
> }
>
> Is this what you intended - it's simpler than reinterpret_cast
> but it's still a little esoteric for what should be a
> commom action. I've attached a copy of a bitmap image
> (height = 480) in case you want to check other possibilities - if
> you do find anything more direct that works for this I would
> be very grateful.
>
> Thanks again,
> Jim
>
> ps Please feel free to post this on the web if you think others
> will find it of interest.
>
> Olav Beckmann wrote:
>
> > Hi,
> >
> > Thanks for letting me know that the problem is basically solved.
> >
> > However, having had a look in detail at your message, I do have a
> > concern. You say that your four-byte bitfield is a structure. This
> > worries me because I am quite sure that there is nothing in the
> > C/C++-standard that forces the compiler to place the elements of a
> > structure in consecutive addresses in memory. In fact, quite a few
> > compilers (I would be surprised if g++ doesn't also do that with certain
> > optimisation flags set) will word-align each field of a structure. This
> > means that on a 32-bit machine, you could find that your 4-byte
> > structure takes 16 bytes of space - because each field of the struct has
> > been aligned to the nearest word-boundary, with the in-between space
> > ignored. I once wrote a program which had a performance bug (i.e. sudden
> > much slower performance than previously), and the way I resolved that
> > was to force the compiler to word-align certain bits in my structs.
> >
> > So - what to do? Why not use an array of 4 unsigned chars? The thing
> > with arrays is that C/C++ doesn't actually "have" arrays. Really, the
> > compiler only knows pointers. The array notation is just "syntactic
> > sugar" for pointer arithmetic. So, if you declare something like
> >
> > unsigned char bits[4];
> >
> > bits[0] =
> > bits[1] =
> >
> > then bits[1] will be translated to *(bits + 1), which is what we want (1
> > byte on from the pointer to the start of the bitfield.
> >
> > [[I am also slightly wondering why it is necessary to have these 4-byte
> > things at all. Is it not possible to read 4 bytes straight into a long
> > *? ]]
> >
> > [[ I also found this link about reinterpret_cast:
> >
> > http://www.google.com/search?q=cache:www.cs.unm.edu/~jalewis/cs108/notes/xtraRTTI/tsld003.htm+reinterpret_cast&hl=en
> >
> > But I have no objection to that in principle.]]
> >
> > OK, 'hope this is useful.
> >
> > PS: Do you mind if I stick a transcript of these emails on my web-page
> > for group projects? I just always feel that I ought to make sure that
> > all groups have access to the same resources...
> >
> > Olav
> >
> > JimStanton wrote:
> > >
> > > Hello Olaf,
> > >
> > > I wonder if you could help me with a problem I am having getting a C++
> > > program to compile and work on the g++/Linux system here.
> > >
> > > The program does work fine on Visual C++/Windows here and on my
> > > g++/Linux system at home, but it seems that on the g++/Linux system here
> > > it does not properly convert a bitfield into an unsigned long inteter.
> > > The function to do this is as follows:
> > >
> > > unsigned long Image::readFourByte(ifstream& in, int l)
> > > {
> > > FOURBYTE number;
> > > unsigned char ch;
> > >
> > > in.clear();
> > > in.seekg(l);
> > >
> > > in.get(ch); number.byte0 = ch;
> > > in.get(ch); number.byte1 = ch;
> > > in.get(ch); number.byte2 = ch;
> > > in.get(ch); number.byte3 = ch;
> > >
> > > return *reinterpret_cast<unsigned long *>(&number);
> > > }
> > >
> > > where FOURBYTE is a struct of 4 unsigned char. The purpose is to read 4
> > > bytes from a file "in" and cast them to an unsigned long.
> > >
> > > The code compiles successfully, but the cast does not work properly. The
> > > executable produced on my system at home does work - I havn't tried this
> > > yet but I assume I could get it to work by producing a statically bound
> > > executable at home (1.4M cf 28k).
> > >
> > > That might work but it seems a poor solution - I'd be very grateful if
> > > you could offer any other suggestions.
> > >
> > > Kind regards
> > > Jim Stanton
> > > jks100 (MSc Conversion)