tags:

views:

127

answers:

5

I have a function which expects a 8 bytes long unsigned char.

void f1(unsigned char *octets)
{
  unsigned char i;
  for (i=0;i<8;i++)
    printf("(%d)",octets[i]);
}

This is how I use it while I have one 64bit integer:

  unsigned long long ull = 1;
  f1((unsigned char *) &ull);

(it uses the machine's native endianness.)

My question is, if instead of having 1x64bit integer, I have 2x32bit integers - is there a way to combine them efficiently as an input for this specific function?

  unsigned long int low = 1;
  unsigned long int high = 0;
+3  A: 

You could just put them in an array:

unsigned long int lohi[2] = {1, 0};
f1((unsigned char *) lohi);

edit: Using existing variables:

unsigned long int lohi[2] = {lo, hi};
tzaman
What if the variables low and high are a given?
Doori Bar
Which means there is no 'efficient' approach of using the original allocation of these variables?
Doori Bar
@Doori Bar: to re-use the original allocation, you need to guarantee that the original allocation is suitable for re-use this way. The way to guarantee this is for the original allocation to use an array, instead of independent variables.
Aidan Cully
+3  A: 

Does a union work portably? If so, it's a good approach...

union {
    struct {
        unsigned char CharArray[8];
    } ub;
    struct {
        unsigned long int IntArray[2];
    } ul;
    unsigned long long ull;
} Foo;
Aidan Cully
The variables "low" and "high" are a given, just like the function. I was wondering if there's an efficient approach to 'combine' their current memory allocation for them to act as a valid input for this specific function?
Doori Bar
If I understand you correctly, then no, there isn't. If the variables are stored adjacent in memory, it might be possible to coerce the address of one of them to a 64-bit type so that the memory used by the 64-bit pointer overlays precisely those two variables, but there's no portable / robust way to guarantee that that will be the case. Consider that the variables may not be stored in memory at all, but rather in CPU registers.
Aidan Cully
I think you could do that with memcpy(), but the compiler would probably optimize it away and it wouldn't affect to the performance.
vtorhonen
+1. the union also avoid possible future problems with the strict aliasing. extra assignments could be optimized out by the compiler if called function is inlined. if function is too big to inline, then the relative cost of extra assignment is negligible.
Dummy00001
@Aidan Cully: So I guess the case is now clear, there is no method to achieve such efficiency. Thanks for your clarification
Doori Bar
+2  A: 

Typecast, bitshift and do bitwise or.

unsigned long int low = 1;
unsigned long int high = 0;
unsigned long long ull = (unsigned long long) high << 32 | low;
vtorhonen
Which means there is no efficient method to do it?
Doori Bar
Simply copying them into adjacent memory as in my or Aidan's answer will likely be faster than this approach. However, you can't really get around making a copy.
tzaman
Bitwise operators are not efficient? What is efficient then?
el.pescado
@el.pescado: As tzaman stated, the alternatives suggested here are more relevant, but as I stated - I wished to use the original allocations, not to apply bitwise operators - yet alone a new allocation as a 64bit placeholder. (my wish is impossible, tho)
Doori Bar
A: 

You can use a combination of union and struct to keep your namings and not using arrays.

union {
    struct {
        unsigned long int   low  = 0;
        unsigned long int   high = 1;
    };
    unsigned long long int  ull;
};

Use low and high as you would do, and use ull when calling f1. But notice that writing it this way, you assume a little endian ordering.

Also note that on Linux anh other UNIXes, in 64 bits mode, both long int and long long int are 64 bits (only int is 32 bits). Of what I know, only Windows has long int as 32 bits in 64 bits mode.

Didier Trosset
The case is a given, so changing the function or the variables for achieving efficient method to handle it - is not valid for said case. My question was rather to learn the right way to handle a specific scenario - Thanks for your input.
Doori Bar
A: 

Different way of looking at it:

void f1( unsigned char* octet )
{
    f2( octet, octet + 4 );
}

void f2( unsigned char* quad1, unsigned char *quad2 )
{
    unsigned char i;
    for (i=0;i<4;i++)
        printf("(%d)",quad1[i]);
    for (i=0;i<4;i++)
        printf("(%d)",quad2[i]);
}

Works better in C++ when both functions can have the same name.

Patrick
But the function is a given, my question was rather to learn the right way to handle a specific scenario - Thanks for your input.
Doori Bar