• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 437
  • Last Modified:

store ints in shorts...

Ok, I give up. I am trying to store an integer (assuming 4 bytes) in 2 shorts (assuming 2 bytes) and then get the integer back again. I tried memcpy()'s and this little bit of code with no luck.
... snip ...
short1 = int1;
short2 = (int1 >> 16) & 0xFFFF;
int2 = (int)((int)((short)short1) |
                  (int)((int)((short)short2) << 16));
... snip ...
Any help is appreciated. mm
0
marvinm
Asked:
marvinm
  • 9
  • 5
  • 3
  • +5
1 Solution
 
abesoftCommented:
Why not do it like this:

union myUnion{
    int theInt;
    struct{
        short one;
        short two;
    } theAlias
} myVar;
myVar.theInt = int1;

And then you can access myVar.theAlias.one (and two) to get at the data.

This keeps your code portable and all that, although it doesn't really account for what happens when sizeof(int) == sizeof( short).  If you want to cover yourself in that case, you should initialize the whole union to 0 when you start.

Hope this helps.
0
 
marvinmAuthor Commented:
I need to store an integer in 2 shorts, and then get an integer form the 2 shorts. I'm not worried about portability. I'm working on a windows machine. Big-Endian, Right?
Thanks, mm
0
 
sgantaCommented:
Hi Marvinm !

I have the solution for your problem. But unfortunately Question is locked.
This works fine. If it is acceptable to you. Please reject the earlier answer.
and accept it.

int int1,int2,int3,temp_int1,temp_int2;
short short1,short2,short3;

/* Assign some value to int1 */


short1 = (int1 >> 16) &0x00FF;       /* Stores the higher 2 bytes */
short2 = int1 & 0x00FF;                /* Stores the lower 2 bytes */

/* To get back the short1 & short2 into integer do the following */

temp_int1 = short1;  /* Or you can say temp_int1 = (int) short1; */
temp_int2 = short2;  

int3 = (temp_int1<<16)|temp_int2;


OR

You can replace the above statement by
int3 = ((int)short1)<<16 | ((int)short2);

The above solutions works fine. I hope this is acceptable to you.

Thank you for GOOD QUESTION.
JESUS LOVES YOU - sganta
0
Free tool for managing users' photos in Office 365

Easily upload multiple users’ photos to Office 365. Manage them with an intuitive GUI and use handy built-in cropping and resizing options. Link photos with users based on Azure AD attributes. Free tool!

 
NorbertCommented:
a little bit much casting
first the length of int is not defined it depends on the machine
and the compiler
int can be 16 bit or 32 bit
therefore for comptibility
long int1;
long int2;
short short1;
short short2;
short1=(short)(int1&0x0ffff);
short2=(short)((int1>>16)&0x0ffff);
int2=((long)short2<<16)|(long)short1;
should work
example:
the long value
0x12345678
short1 contains 0x5678
short2 contains 0x1234
((long)short2<<16)=0x12340000;
what you coded shold work
so where is your problem ?
0
 
marvinmAuthor Commented:
This program results in:
before <99867> after <65563>
int main(void)
{
      short s1,s2;
      int   i1,i2;

      i1 = 99867;
      s1 = (i1 >> 16) & 0x00FF;
      s2 = i1 & 0x00FF;
      i2 = ((int)s1) << 16 | ((int)s2);
      printf("before <%d> after <%d>\n",i1,i2);
      return 0;
}

0
 
sgantaCommented:
Have you tested my answer
Which I had posted as a COMMENT
0
 
marvinmAuthor Commented:
sganta:
The program I posted above as a comment is essentially your answer, isn't it? - mm
0
 
sgantaCommented:
Yes ! Now I am posting as an answer.

      I have the solution for your problem. But unfortunately Question is locked.
      This works fine. If it is acceptable to you. Please reject the earlier answer.
      and accept it.

      int int1,int2,int3,temp_int1,temp_int2;
      short short1,short2,short3;

      /* Assign some value to int1 */


      short1 = (int1 >> 16) &0x00FF;       /* Stores the higher 2 bytes */
      short2 = int1 & 0x00FF;                /* Stores the lower 2 bytes */

      /* To get back the short1 & short2 into integer do the following */

      temp_int1 = short1;  /* Or you can say temp_int1 = (int) short1; */
      temp_int2 = short2;  

      int3 = (temp_int1<<16)|temp_int2;


      OR

      You can replace the above statement by
      int3 = ((int)short1)<<16 | ((int)short2);

      The above solutions works fine. I hope this is acceptable to you.

      Thank you for GOOD QUESTION.
      JESUS LOVES YOU - sganta
0
 
marvinmAuthor Commented:
sganta:
if I set int1 to 99867, then intt3 becomes 65563?
0
 
sgantaCommented:
Hi !

Can you try this.

int3 = ((temp_int1<<16)& 0Xff00)|(temp_int2 & 0X00FF)

I 've checked my earlier solution but it works fine.
OK, You try this. I hope this should work.
0
 
marvinmAuthor Commented:
That comes out with 27 for 99867. I've tested on a windows 95, and an SCO UNIX box.
0
 
sgantaCommented:
Can you display the output values
for short1,short2,temp_int1,temp_int2
and get back to me.
Thanks
0
 
abesoftCommented:
I'm not sure how my answer missed your question, but I thought that you wanted to get at the contents of an int as two shorts...

Taking my union:
    union myUnion{
        int theInt;
        struct{
            short one;
            short two;
        } theAlias;
    } myVar;

You could re-write the code from your original question:
short1 = int1;
short2 = (int1 >> 16) & 0xFFFF;
int2 = (int)((int)((short)short1) |
                  (int)((int)((short)short2) << 16));
to read:
myVar.theInt = int1;
/* Now, read or set myVar.theAlias.one */
short1 = myVar.theAlias.one;
short2 = myVar.theAlias.two;
int2 = myVar.theInt;

So, my question is: what am I missing?  What are you trying to do that I wasn't providing?  Did you really want to use that many casts....
If you like casts, try
    short1 = (*(myUnion*) &int1).theAlias.one;
    short2 = (*(myUnion*) &int1).theAlias.two;

0
 
marvinmAuthor Commented:
short1 = tmp_int1 = 1
short2 = tmp_int2 = 27
0
 
marvinmAuthor Commented:
abesoft:
All the casting was just to try to fix what wasn't working.
My problem is the way that I was storing an int in 2 shorts, and then creating an int was not working. Using your union idea is fine; however, I was looking for a response as to why my code failed. Thanks, mm
0
 
imladrisCommented:
I'm not quite clear on why sganta's code is not providing you with the result you're after.

However, as to the why, the crux of the problem lies in how shifting and sign extension work. When a short is cast to an int, since they are both signed, sign extension will occur. So an short which has the top bit set (which therefore appears to be a negative number) will propogate that through the top 16 bits when it is cast to an int (so that it will also be negative).

The other snare in this kind of stuff is that if you left shift a short by 16 it will wind up being 0. You have to be sure to cast it to an int before the shift occurs.

0
 
PhilCCommented:
You could use a character buffer inbetween
int integer1,integer2;
short short1,short2;
char buf[10];

memcpy(buf,&integer1,sizeof(int));
memcpy(&short1,buf,sizeof(short));
memcpy(&short2,buf+sizeof(short),sizeof(short));
memcpy(buf,&short1,sizeof(short));
memcpy(buf+sizeof(short),short2,sizeof(short));
memcpy(&integer2,buf,sizeof(int));

here integer1 = integer2.
0
 
ozoCommented:
short1 = int1;
short2 = (int1 >> 16);
int2 = (short1&0xffff) | (short2<<16);

0
 
RONSLOWCommented:
sganta's code used 0x00ff instead of 0xffff (ie one byte instead of two).

0
 
marvinmAuthor Commented:
Still no luck. I was sing 0xffff, it dont work.
ozo, I get the same incorrect results from your solution. (It is essentially the code I posted, without all the casts.
Using an intermediate character buffer works, but seems like there should be another way.
0
 
ozoCommented:
are you saying that
  long int1=99867;
  short short1 = int1;
  short short2 = (int1 >> 16);
  long int2 = (short1&0xffff) | (short2<<16);
  printf("%ld\n",int2);
gives 27?
I don't understand how a conforming c compiler can do that.
please tell us what you get from
  printf("%ld\d",int2 = (short1&0xffff));
  printf("%ld\n",int2 = (short2<<16));

0
 
marvinmAuthor Commented:
Ozo: you're answer worked fine, I'm not sure how I tested it, but I must have screwed something up. The buffer answer works fine and is the easiest for me to understand. I'm still not clear on how the bitwise operations come up with the correct answer.

Sganta's answer comes up with the answer 27. Here's what I finally tested, and the output:
#include <stdio.h>

int main(void)
{
  int int1=99867,int2,tmp_int1,tmp_int2;
  short short1,short2;

  printf("my origional:\n");
  short1=int1;
  short2=(int1>>16) & 0xFFFF;
  int2=(int)((int)((short)short1)|(int)((int)((short)short2)<<16));
  printf("short1 <%d> short2 <%d> int1 <%d> int2 <%d>\n",short1,short2,
                                                                int1,int2);
  printf("sganta first:\n");
  short1=(int1>>16) & 0x00FF;
  short2=int1&0x00FF;
  int2=((int)short1<<16)|short2;
  printf("short1 <%d> short2 <%d> int1 <%d> int2 <%d>\n",short1,short2,
                                                                int1,int2);
  printf("sganta second:\n");
  tmp_int1=short1;
  tmp_int2=short2;
  int2=((tmp_int1<<16)&0xff00)|(tmp_int2&0x00FF);
  printf("short1 <%d> short2 <%d> int1 <%d> int2 <%d>\n",short1,short2,
                                                                int1,int2);
  printf("ozo first:\n");
  short1=int1;
  short2=(int1>>16);
  int2=(short1&0xffff)|(short2<<16);
  printf("short1 <%d> short2 <%d> int1 <%d> int2 <%d>\n",short1,short2,
                                                                int1,int2);
  return 0;
}
my origional:
short1 <-31205> short2 <1> int1 <99867> int2 <-31205>
sganta first:
short1 <1> short2 <27> int1 <99867> int2 <65563>
sganta second:
short1 <1> short2 <27> int1 <99867> int2 <27>
ozo first:
short1 <-31205> short2 <1> int1 <99867> int2 <99867>
0
 
ozoCommented:
Well, in yoour original, (int)short1 sign extended from 0x861b to 0xffff861b.
(int)((unsigned short)short1) could have fixed that.

sganta first has the problem that RONSLOW pointed out.
using 0xFF instead of 0xFFFF made 0x861b&0xff = 0x1b
sganta second repeats the problem and also makes 0x1b0000&0xff00 = 0

my first undoes the sign extend with (int)short1&0xffff
(or using unsigned shorts could have obviated the need for that)

the memcpy version could be simplified to

   memcpy(&short1,&integer1,sizeof(short));
   memcpy(&short2,(char *)&integer1+sizeof(short),sizeof(short));

   memcpy(&integer2,&short1,sizeof(short));
   memcpy((char *)&integer2+sizeof(short),&short2,sizeof(short));
0

Featured Post

The eGuide to Automating Firewall Change Control

Today’s IT environment is constantly changing, which affects security policies and firewall rules. Discover tips to help you embrace this change through process improvement & identify areas where automation & actionable intelligence can enhance both security and business agility.

  • 9
  • 5
  • 3
  • +5
Tackle projects and never again get stuck behind a technical roadblock.
Join Now