|
From: Mac R. <re...@no...> - 2002-06-10 16:36:27
|
A few thoughts:
1. You can't shift bits in a float or double because not all bit patterns
are legal in the IEEE floating point representation. Also, shifting bits
in floats/doubles would move bits from the mantissa into the exponent, or
from the exponent into the mantissa, which is unlikely to be meaningful.
2. It may be that the shifts are taking place in a variable of the original
type. If that is true, then if you shift a 'char' value up by more than 8
bits, you will have shifted it entirely out of the temporary variable type.
Copy the value into a bigger int first, and then perform the shift.
Example from your code:
>short int mask =3D 65535;
>int zorro =3D mask + (mask << 15);
a. mask starts out filled : 0xFFFF
b. Then you shift it 15 bits over (instead of 16, which seems odd), which
shifts all of the bits out except for what used to be the least significant
bit: 0x8000
c. Now you add that to the original mask causing a roll off the high end:
0xFFFF + 0x8000 =3D 0x7FFF
d. Assignment to zorro yields : 0x00007FFF
As a general rule, I would recommend using 'long' explicitly rather than
'int' to avoid future portability problems. Since you are requiring 32
bits of storage, you should use a type that also has a practical guarantee
of 32 bits (I don't remember what the real standard requirement is, but
getting into the full checking is somewhat more involved). So if you
replaced the second line of code with the following, it *should* work:
long zorro =3D (long)mask + ((long)mask << 16);
or:
long zorro =3D mask;
zorro <<=3D 16;
zorro |=3D mask;
3. Also watch out for sign extension. If the result you are getting for
mask is not 0x00007FFF, then the compiler may be promoting the temporary
variables up to a larger size before doing the shifts, which will protect
your bits, but has other problems.
Example from your code:
>short int mask =3D 65535;
>int zorro =3D mask + (mask << 15);
Since mask and zorro are both signed, promotion will take place in signed
integers. The first major thing that I should have noticed sooner is that
you stored 65535 in a 'signed short int'. If you were to print out the
value of mask, you would *NOT* get 65535, you would get -1. By setting the
top bit, you have moved the value into the negative realm. So here's what
happened:
a. mask gets bit value 0xFFFF (-1)
b. During shifting, mask gets promoted to long so that bits are not lost.
Promotion *MUST* maintain the logical value (-1), so the compiler performs
sign extension. The temporary version of mask becomes the long version of
-1 : 0xFFFFFFFF
c. That temporary gets shifted up 15 bits : 0xFFFF8000
d. That gets added to another temporary, long, sign extended version of
mask : 0xFFFFFFFF + 0xFFFF8000 =3D 0xFFFF7FFFF (according to Windows=
Calculator)
The lesson here is that if you are going to play with bits and shifting,
*ALWAYS* work in unsigned variables :=20
unsigned short int mask =3D 65535; // I would prefer 0xFFFF for clarity...
unsigned long int zorro =3D mask + (mask << 16);
4. If you are just trying to get an array of bytes into a short, int, long,
float, or double, remember that memcpy is your friend.
memcpy(&MyLong, MyArrayOfBytes, 4); // array is already an address
or
memcpy(&MyLong, &MyStructureOfBytes, 4);
There are a *LOT* of things you have to keep in mind when playing this sort
of game. First, the memcpy method is hopelessly unportable. Byte ordering
inside multibyte variables changes on different machine types, so any given
ordering of bytes in the array will only work for certain types of
machines, but would at least work on those machines no matter which
compiler you used. Secondly, the memory packing of structures is undefined
by the standards, so different compilers are allowed to pack them pretty
much any way they want. The memcpy from a struct would only work for a
particular compiler, and might break in the next version.
If you're going to risk the major unportability problems of memcpy, you
might as well just drop to inline assembly and be explicit about the whole
thing. But there might be some meaningful reason. About the only thing
that comes to mind is if you had to work with some kind of storage API that
only accepted a pointer to chars, and you *KNEW* that both programs were
going to use the same memory layout...
Sample portable code, assuming that Bytes[4] has the most significant byte
in [0] and the least significant byte in [3]. This will work on *ANY*
machine or compiler. If the most/least significant bytes are in the other
order, run the loop the other way...
MyLong =3D 0;
for (int i=3D0; i<4; i++)
{
MyLong <<=3D 8;
MyLong |=3D MyArrayOfBytes[i];
}
I have to get back to work. Hopefully that made some kind of sense, and
was useful.
Mac
At 09:23 PM 6/8/02 +0200, Carlos Garc=EDa del Monte wrote:
>Hi:
>I have problem I want solve by bit shifts. Below I add the code (one of
>the many versions I tried) so you can see it and know better what I am
>searching. The thing I cannot do at any way is the shifting phase
>(obviously, if not the subject would have been another).
>I want take some bytes and put them in a variable with more than one
>byte of width. For example, a double or a long double variable.
>So I try unsigned char unschar; I make an struct with eight unschar, I
>assign the first eight bits to the first and shift it 7*8 places when
>assigning to double, the next 8 bits to the second, shifting eight bits
>less, and so on. But everyone except the last "warning shift is >=3D than
>the width of the type". The same if I try with unsigned int.
>If I try changing unchars by doubles, so they have the size I need for
>the shifts and that warning cannot appear, but then "error using double
>with int in binary >> operator". If I use with variables two doubles it
>says the same error "using double with double in >> binary operator".
>If I change to a struct with void varname:64; error because void is not
>"forgotten" (I don't remember the exact word), or there is no cast to
>int (in which case I have again the problem of shifting more than the
>width of the type, I suppose, in the trial of this it still says error
>because the buffer is void type or if I try int tal:64, then it exceeds
>its type).
>Finally, with temp as *unschar, the void_type{ int pues:64;}vacio;, I
>read with temp, assign it with (int) cast to pues and shift pues it
>reads it wrong and creates and error, windows has to close it.
>With long double it says no more than 64 width bitfields.
>Is there some way to do that and not having to be oneself who reads the
>bits?
>
>Here are the sizeofs of my computer:
>char: 1
>unsigned char: 1
>unsigned long int: 4
>short int: 2
>short: 2
>unsigned short int: 2
>int: 4
>float: 4
>double: 8
>unsigned char: 1
>unsigned int: 4
>long int: 4
>long double: 12
>
>The program:
>
>#include <iostream.h>
>#include <stdlib.h>
>#include <math.h>
>#include <fstream.h>
>#include <stdio.h>
>
>typedef struct new_doble{
>unsigned int dospri;
>unsigned int dosult;
>}doble;
>
>typedef struct signed_doble{
>int sig1;
>int sig2;
>}siged;
>
>typedef struct novo_dos{
>unsigned char uno;
>unsigned char dos; //These two are from a trial with double, trying to
>make a double with all 1 I get only 1.447e+09
>unsigned char tres;
>unsigned char cuatro;
>unsigned char cinco;
>unsigned char seis;
>unsigned char siete;
>unsigned char ocho;
>}dos;
>
>typedef struct complet{
>double every;
>};
>
>typedef struct char_type{
>unsigned char hype:64;
>}extra;
>
>typedef struct void_type{
>int pues:64;//This was void in the previous trials
>}vacio;
>
>int main()
>{
>doble pares;
>siged coplus;
>dos octos;
>complet all;
>int pri, ult;
>long double hala;
>double tal;
>double test =3D 747665.4576;
>unsigned char mascara =3D 255;
>short int mask =3D 65535;
>int zorro =3D mask + (mask << 15);
>double temp;
>unsigned char *pol;
>vacio nada;
>extra largo;
>fstream outFile;
>fstream inFile;
>FILE *fuera;
>FILE *dentro;
>
>cout << "zorro " << zorro << '\t' << mask << endl;
>outFile.open("shifting", ios::out);
>if(!outFile){
>cout << "shifting no abre" << endl;
>exit(1);
>}
>outFile << test;
>outFile.close();
>if((fuera =3D fopen("shifting", "r")) =3D=3D NULL){
>cout << "shiftin2 no abre" << endl;
>exit(1);
>}
>fseek(fuera, 0, SEEK_END);
>int size;
>size =3D ftell(fuera);
>rewind(fuera);
>int tanto =3D 55;
>while(!feof(fuera) && tanto >=3D 0){
>fread(pol, 1, 8, fuera);
>nada.pues=3D(int)pol;
>tal =3D nada.pues << tanto;
>tanto-=3D8;
>}
>fclose(fuera);
>
>cout << test << '\n' << tal;
>
>
>system("PAUSE");
>return 0;
>}
>
>
>_______________________________________________________________
>
>Don't miss the 2002 Sprint PCS Application Developer's Conference
>August 25-28 in Las Vegas -
http://devcon.sprintpcs.com/adp/index.cfm?source=3Dosdntextlink
>
>_______________________________________________
>Dev-cpp-users mailing list
>Dev...@li...
>https://lists.sourceforge.net/lists/listinfo/dev-cpp-users
>
-
_____________________________ /"\
Mac Reiter \ / ASCII Ribbon Campaign
Nomadics, Inc. X Against HTML Mail
re...@no... / \ (To join the campaign, simply use
this in your signature.)
=20
|