1

For a homework question, i need to convert 64 bit int from host to network order in C. 64 bit int is stored in a union(as coded below) and is generated randomly by id_generator(see below). I'm trying to convert its order with the nw_order function and when i print it to control the order, they are just zeros. For example i get this output:

host order: 6D 5F E5 31

net order: 0 0 0 0

So, what i'm missing here?

union u
{
    uint64_t u64;
    uint32_t u32[2];

};

nw_order function takes two arguments and assign converted order of the first argument to the second:

void nw_order(const union u *host, union u *net)
{

   net -> u32[0] = htonl(net->u32[1]);
   net -> u32[1] = htonl(net->u32[0]);

}

i don't know if it causes problem but random generator function is:

uint64_t id_generator()
{
 union u clientid;

 if(sizeof(long) > 7)
  clientid.u64 = (uint64_t)random();
 else
 {
   clientid.u32[0] = (uint32_t)random();
   clientid.u32[1] = (uint32_t)random();
 }

 return clientid.u64;

}

And the main function that prints before and after convertion:

int main()
{

   union u client_id;
   union u net;
   unsigned char* p;


   srandom(time(NULL));

   client_id.u64 = (uint64_t) id_generator();

   p = (unsigned char *) &client_id.u64;

   printf("host order: %X %X %X %X\n",*p,*(p+1),*(p+2),*(p+3)); /* host ord*/

   nw_order(&client_id, &net);

   p = (unsigned char *) &net.u64;

   printf("net order: %X %X %X %X\n",*p,*(p+1),*(p+2),*(p+3)); /* network ord*/


   return 0;
} 
user3717434
  • 215
  • 4
  • 19
  • Typo in your `nw_order` function - you both read from and write to the `net` argument. You should presumably be reading from `host` instead. – simonc Jul 01 '14 at 16:03
  • See http://stackoverflow.com/questions/3022552/is-there-any-standard-htonl-like-function-for-64-bits-integers-in-c – chux - Reinstate Monica Jul 01 '14 at 16:19
  • add also here, i have written it wrong, i was not my intention. they should be: `net -> u32[0] = htonl(host->u32[1]); net -> u32[1] = htonl(host->u32[0]);` But it prints all zeros also in this case – user3717434 Jul 01 '14 at 16:29

1 Answers1

3
void nw_order(const union u *host, union u *net)
{
   net -> u32[0] = htonl(net->u32[1]);
   net -> u32[1] = htonl(net->u32[0]);
}

You are only using the pointer to net here:

This sets the low 4 bytes to the byte-reversed high 4 bytes and the high four bytes to the twice byte-reversed high 4 bytes <=> to their previous content.
Not what you wanted, right?

Anyway, better do it thus:

uint64_t nw_order(const uint64_t in) {
    unsigned char out[8] = {in>>56,in>>48,in>>40,in>>32,in>>24,in>>16,in>>8,in};
    return *(uint64_t*)out;
}

This has two advantages:

  • Also works on big-endian (You might not care, if you are only on x86)
  • Does not needlessly use pointers.

Also consider that random() only returns an int, and does not use the full range: Check RAND_MAX. Anyway, this function is not of reliable quality for anything but quick joke-programs.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
  • Ups.. yes it should be net -> u32[0] = htonl(host->u32[1]); But also in this case it gives me zeros... – user3717434 Jul 01 '14 at 16:10
  • thanks a lot for the answer, but i need to use this union. with the code you suggest, is it ok passing just "client_id->u64" as the parameter to the function? – user3717434 Jul 01 '14 at 16:15
  • @chux: Already incorporated in my expanded answer while you wrote the comment. Thanks though. – Deduplicator Jul 01 '14 at 16:15
  • @user3717434: Sure. Why do you have to use the union though? FYI: This function (like the standard ones) works for both directions. – Deduplicator Jul 01 '14 at 16:16
  • @Deduplicator, bcs i need to generate a random 64 bit int. Random returns a long so it's not guaranteed to be 8 byte. I use union to catch both cases(4 byte and 8 byte). What do you suggest? Thanks. – user3717434 Jul 01 '14 at 16:26
  • Please don't use pointer casts like that... While it's a common pattern, strictly speaking it's undefined behavior. Just use memcpy. The compiler will optimize it. `uint64_t result; memcpy(&result, out, 8); return result;` – pdw Jul 02 '14 at 09:46
  • @pwd: It's the same in green. Doesn't matter that the standard has an example using `memcpy`. – Deduplicator Jul 02 '14 at 09:47