tags:

views:

103

answers:

4

hi

Imagine that I have the following variables:

unsigned long a = 1;    //32-bit value
unsigned short b = 1;   //16-bit value
unsigned char c ='\x01' //8-bit value

unsigned char buffer[7];

Now I would like to map or combine those variables above in the buffer as follows: first four bytes should be occupied by value of int a, next 2 bytes by value b and the last byte by c.

==> buffer = 0x 00000001 0001 01

Is here anyone aware of an easy way to do that in C++? At the moment I am having help function that return the byte pattern for shorts and integers but I guess in C++ there must be a better way to do that?

Thanks

+2  A: 
*(unsigned long*)(buffer+0) = a;
*(unsigned short*)(buffer+4) = b;
*(unsigned char*)(buffer+6) = c;

Note however, that on some CPU architectures (though not x86), this will fail due to alignment issues. On x86 it will just cause some inefficiency in memory transactions.

EFraim
Downvote, why?
EFraim
A: 

It's messy, but:

Going into buffer

buffer[ 0 ] = ( unsigned char ) a;
buffer[ 1 ] = ( unsigned char )( a >> 8 );
buffer[ 2 ] = ( unsigned char )( a >> 16 );
buffer[ 3 ] = ( unsigned char )( a >> 24 );
buffer[ 4 ] = ( unsigned char ) b;
buffer[ 5 ] = ( unsigned char )( b >> 8 );
buffer[ 6 ] = c;

Coming out of buffer

a = buffer[ 0 ] | ( buffer[ 1 ] << 8 ) | ( buffer[ 2 ] << 16 ) | ( buffer[ 3 ] << 24 );
b = buffer[ 4 ] | ( buffer[ 5 ] << 8 );
c = buffer[ 6 ];
David French
+4  A: 

Use a union

#include <iostream>
struct MyStructData   
{
    unsigned long  a;
    unsigned short b;
    unsigned char  c; 
};
union Swap
{
     MyStructData   data;
     char           buffer[7];// Can use [sizeof(MyStructData)]
};

int main()
{
    Swap  data;
    data.data.a = 1;
    data.data.b = 1;
    data.data.c = 1;

    for(int loop=0;loop < 7;++loop)
    {
        std::cout << "buffer(" << loop <<")  = (" << (int)data.buffer[loop] << ")\n";
    }
}
Martin York
+1 for reading my mind.
Evan Teran
#pragma pack, anybody?
EFraim
+1, but I would also use "#pragma pack(1)" as noted above
gatorfax
You might also want to consider making MyStructData a bitfield to ensure you get 32, 16, and 8 bits packed correctly as well.
gatorfax
#pragma is only a hint, and thus is not guranteed to be used by the compiler. I think using Bitfields will gurantee that it is packed but I don't know for sure. Anybody with a copy of the standard care to quote chapter and verse.
Martin York
But it packs correctly with no space and no hints on my machine.
Martin York
Using bitfields alone does not guarantee packing. I've been bitten by that before using the ICC.
gatorfax
@Martin: is there a source for pragma pack just being a hint? I would think a lot of system software would be potentially broken if a compiler decided not to honor it
Evan Teran
@Evan: The #pragma directives offer a way for each compiler to offer machine- and operating system-specific features while retaining overall compatibility with the C and C++ languages. Basically the compiler ignores any #pragma directives it does not understand as it is not part of the language. http://msdn.microsoft.com/en-us/library/d9x1s805(VS.71).aspx
Martin York
@Evan: Also note #pragma is actually part of the pre-processor not the C/C++ language.
Martin York
@Martin: sure, that part I agree with. But you have implied that despite the fact that msvc has a #pragma pack directive, it may not honor it. Which to be honest, I doubt you were trying to imply because that would mean there is a LOT of broken system level code out there. I think what you meant was something like "...thus is not guaranteed to be used by all compilers". (for simplicity sake, when I say compiler here, I mean the preprocessor, compiler proper and linker). We all agree that #pragmas are toolchain specific :-).
Evan Teran
@Everybody: I did not mean to imply that compiler may choose to ignore pragmas. I was just trying to pointing out that pragma is compiler specific. Saying that you should use #pragma pack is not valid as it may have no meaning to your specific compiler. You should use the appropriate compiler specific command that makes it pack the structure for you. If you are on Windows using DevStudio then it may be usefull to specicify pragma pack.
Martin York
+1  A: 

in addition to the other answers (which look fine), you can do something like this (note depending on arch, you may need to reorder the contents of the struct. you may also need to enable packing to ensure no padding is inserted between members):

union {
    struct {
        int   int_value;
        short short_value;
        char  char_value;
    } values;
    char buffer[sizeof(values)];
} x;

x.values.int_value   = a;
x.values.short_value = b;
x.values.char_value  = c;
Evan Teran
Generally you MUST enable packing. Pretty much every architecture today is at least 32-bit aligning. And BTW, at least in VC++, putting the int_value first, will force 32-bit alignment for all struct members.
EFraim
@EFrain: Plainly not true as it aligns correctly with no hints on my machine. If the order were reversed then I would suspect that it would not pack correctyl because of alignment issues.
Martin York
@Marfin: Yes, with int_value first it might align properly on VC++. Not on GCC. The point is that when reversed it won't align even on VC++. Thus you can't trust this solution without pack.
EFraim