Convert four chars to a long and a long to four chars
Author Message
Convert four chars to a long and a long to four chars

if i have an array of four chars, how can i make it a long?
the reason i want to do it (transfering numbers on the net) is not c
related BUT MY QUESTION IS SO DONT "FLAME" ME

(btw, long = four bytes; char = 1 byte; in case thats platform specific)

what i want to do can be understood from this:
unsigned long thelong = 1002;
char thechars[4];

//how do i do this?
thechars = thelong

//and this
thelong = thechars

//replace the equals signs with an explanation please! :-)

thanks for all your help everyone
-joe

--
Posted via CNET Help.com
http://www.*-*-*.com/

Mon, 26 Jan 2004 17:30:17 GMT
Convert four chars to a long and a long to four chars

Quote:
> if i have an array of four chars, how can i make it a long?
> the reason i want to do it (transfering numbers on the net) is not c
> related BUT MY QUESTION IS SO DONT "FLAME" ME

It's a C question, worry not.

Quote:
> (btw, long = four bytes; char = 1 byte; in case thats platform specific)

It is indeed. As is "chars have 8 bits", and "the lowest addressed char
is the most significant part of the long".

Quote:
> what i want to do can be understood from this:
> unsigned long thelong = 1002;
> char thechars[4];

> //how do i do this?
> thechars = thelong

> //and this
> thelong = thechars

> //replace the equals signs with an explanation please! :-)

Bit by bit; or rather, byte by byte.

#include <limits.h>

unsigned long charsToLong( unsigned char *theChars )
{
return
((unsigned long) theChars[0] << 24)
| ((unsigned long) theChars[1] << 16)
| ((unsigned long) theChars[2] << 8)
| ((unsigned long) theChars[3])
;
}

void longToChars( unsigned long it, unsigned char *theChars )
{
theChars[0] = (it >> 24);
theChars[1] = (it >> 16);
theChars[2] = (it >> 8);
theChars[3] = it;
}

EXERCISES.

(a) bytes are CHAR_BITS wide [from limits.h]; revise the code so that
the shifts take this into account.

(b) longs need not be 4 bytes wide; revise the code to take this
into account. Is a loop needed? How likely is it we can do without
one? How good is your compiler at unrolling, and does it matter?

(c) the author of this code makes no warrenty as to its effectiveness.
Is his paranoia justified?

--
Chris "electric hedgehog" Dollin
C FAQs at: http://www.faqs.org/faqs/by-newsgroup/comp/comp.lang.c.html

Mon, 26 Jan 2004 18:04:04 GMT
Convert four chars to a long and a long to four chars

Quote:

>  if i have an array of four chars, how can i make it a long?
>  the reason i want to do it (transfering numbers on the net) is not c
>  related BUT MY QUESTION IS SO DONT "FLAME" ME

>  does anyone have an answer?

>  (btw, long = four bytes; char = 1 byte; in case thats platform specific)

sizeof (char) is always 1, but CHAR_BIT may be greater than 8. The
long type must be at least 32 bits wide.

Quote:
>  what i want to do can be understood from this:
>  unsigned long thelong = 1002;
>  char thechars[4];

Better make those unsigned chars.

Quote:
>  //how do i do this?
>  thechars = thelong

>  //and this
>  thelong = thechars

You could try mempcy() or something similar, but you might run into
endianness issues.
You could build on this code:

#include <stdio.h>
#include <limits.h>

int main(void)
{
unsigned long l, temp;
unsigned char c[sizeof l];
size_t i;

l = 0xabcdef01UL;
printf("l: %lx\n", l);
printf("c: ");
for (i = 0; i < sizeof l; i++)
{
temp = l & ((unsigned long) UCHAR_MAX << CHAR_BIT * i);
c[i] = temp >> (CHAR_BIT * i);
printf("%02x ", (unsigned int) c[i]);
}
putchar('\n');

l = 0;
for (i = 0; i < sizeof l; i++)
{
l |= c[i] << CHAR_BIT * i;
}
printf("l: %lx\n", l);

return 0;

Quote:
}

HTH,
Gergo

--
QOTD:
How can I miss you if you won't go away?

Mon, 26 Jan 2004 18:13:01 GMT
Convert four chars to a long and a long to four chars

Quote:

>if i have an array of four chars, how can i make it a long?
>the reason i want to do it (transfering numbers on the net) is not c
>related BUT MY QUESTION IS SO DONT "FLAME" ME

>(btw, long = four bytes; char = 1 byte; in case thats platform specific)

>what i want to do can be understood from this:
>unsigned long thelong = 1002;
>char thechars[4];

#include <limits.h>
unsigned long strlong(char *s) {
unsigned long r = 0; int i;
unsigned chars *S = (unsigned char*)s;
for (i=0; i<sizeof r && *S; i++) {
r = (r<<CHAR_BIT) | *S++;
}
return r;
}
char *longstr(unsigned long l) {
static char r[(sizeof l)+1];
char *R = r + (sizeof l)+1;
*R-- = 0;
while (R>r && l!=0) {
*R-- = l; l >>= CHAR_BIT;
}
return R;
}

on irix and gnu compilers strlong("xyzq")=='xyzq'
some compilers may reject multicharacter literals
or store the bytes in a different order

Mon, 26 Jan 2004 18:11:38 GMT
Convert four chars to a long and a long to four chars

Quote:

> if i have an array of four chars, how can i make it a long?
> the reason i want to do it (transfering numbers on the net) is not c
> related BUT MY QUESTION IS SO DONT "FLAME" ME

> does anyone have an answer?

> (btw, long = four bytes; char = 1 byte;
> in case thats platform specific)

It is platform specific.

Quote:
> what i want to do can be understood from this:
> unsigned long thelong = 1002;
> char thechars[4];

For starters, use unsigned char instead of char,
whenever you're manipulating bytes and or bits.

Quote:
> //how do i do this?
> thechars = thelong

> //and this
> thelong = thechars

Is the high byte of thelong, thechars[0] or thechars[3]?

--
pete

Mon, 26 Jan 2004 18:09:02 GMT
Convert four chars to a long and a long to four chars

Quote:

> unsigned long thelong = 1002;
> char thechars[4];

Make it an array of unsigned char.

Quote:
> //how do i do this?
> thechars = thelong

thechars[0] = (thelong >> 24) & 0xFF;
thechars[1] = (thelong >> 16) & 0xFF;
thechars[2] = (thelong >>  8) & 0xFF;
thechars[3] = (thelong >>  0) & 0xFF;

Quote:
> //and this
> thelong = thechars

thelong = ((unsigned long) thechars[0] << 24)
| ((unsigned long) thechars[1] << 16)
| ((unsigned long) thechars[2] <<  8)
| ((unsigned long) thechars[3] <<  0);

These are portable ways to encode an at most 32-bit unsigned
integer to big-endian format and decode it back.  If the unsigned
long type of some platform has more than 32 bits, these
statements ignore the extras.  Likewise, if unsigned char has
more than 8 bits, these statements leave the extra bits zero.

If you need little-endian format, swap the array indexes around.

Mon, 26 Jan 2004 18:04:17 GMT
Convert four chars to a long and a long to four chars

Quote:

> if i have an array of four chars, how can i make it a long?
> the reason i want to do it (transfering numbers on the net) is not c
> related BUT MY QUESTION IS SO DONT "FLAME" ME

> does anyone have an answer?

> (btw, long = four bytes; char = 1 byte; in case thats platform specific)

It is indeed platform-specific. The only thing you are guaranteed is
that chars are at least 8 bits but maybe more, and longs are at least 32
bits but maybe more.

Furthermore, you should be aware that not all platforms use the same
byte ordering:

16909060 (decimal) is represented by some platforms as 0x01020304 and by
others as 0x04030201, and those aren't the only two possibilities!

Quote:
> what i want to do can be understood from this:
> unsigned long thelong = 1002;
> char thechars[4];

> //how do i do this?
> thechars = thelong

> //and this
> thelong = thechars

> //replace the equals signs with an explanation please! :-)

The easiest way is to cheat. That you are using unsigned long makes
things easier. :-) But do make thechars unsigned as well:

unsigned long thelong = 1002;
unsigned char thechars[sizeof(long)] = {0}; /* = {0} zeroes out the
array */

unsigned char *p, *q;
size_t i;

p = (unsigned char *)&thelong;
q = thechars;

for(i = 0; i < sizeof thelong; i++)
{
*q++ = *p++;

Quote:
}

but this solution does depend upon byte ordering. You can get
byte-ordering-independent code fairly easily (or rather, you can
normalise the byte ordering), simply by exploring each bit:

#include <limits.h>

int main(void)
{
unsigned long thelong = 1002;
unsigned char thechars[sizeof(long)] = {0};
int bit = 0;

while(thelong > 0)
{
thechars[bit / CHAR_BIT] |= ((thelong & 1) << (bit % CHAR_BIT));
thelong >>= 1;
++bit;
}

return 0;

Quote:
}

Not tested, or even compiled, so be wary of loop boundary condition
bugs.

If this gives you the bits in the opposite order to the one you prefer,
simply change int bit = 0; to int bit = sizeof thelong, move ++bit to be
the first statement in the loop, and change it to --bit.

--

"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton

Mon, 26 Jan 2004 18:36:20 GMT
Convert four chars to a long and a long to four chars

I'm piggybacking, rather than responding to Richard. A bit of experimenting
sugested this:

static unsigned long charsToLong( unsigned char *them )
{
register unsigned long result = 0;
if (sizeof (unsigned long) > 0) result = (result << CHAR_BIT) | them[0];
if (sizeof (unsigned long) > 1) result = (result << CHAR_BIT) | them[1];
if (sizeof (unsigned long) > 2) result = (result << CHAR_BIT) | them[2];
if (sizeof (unsigned long) > 3) result = (result << CHAR_BIT) | them[3];
if (sizeof (unsigned long) > 4) result = (result << CHAR_BIT) | them[4];
if (sizeof (unsigned long) > 5) result = (result << CHAR_BIT) | them[5];
if (sizeof (unsigned long) > 6) result = (result << CHAR_BIT) | them[6];
if (sizeof (unsigned long) > 7) result = (result << CHAR_BIT) | them[7];
return result;
}

So long as sizeof(unsigned long) <= 8, which covers all the machines I
dare think about, this does it portably and with no loops. If your compiler
won't optimise away the sizeof tests, either turn up the optimisation
level a tad or get a better compiler.

Critiques requested.

--
Chris "now, where's that mask ... and the cloak ... and the ring ..." Dollin
C FAQs at: http://www.faqs.org/faqs/by-newsgroup/comp/comp.lang.c.html

Mon, 26 Jan 2004 19:19:34 GMT
Convert four chars to a long and a long to four chars

Quote:

> I'm piggybacking, rather than responding to Richard. A bit of experimenting
> sugested this:

> static unsigned long charsToLong( unsigned char *them )
>     {
>     register unsigned long result = 0;
>     if (sizeof (unsigned long) > 0) result = (result << CHAR_BIT) | them[0];
>     if (sizeof (unsigned long) > 1) result = (result << CHAR_BIT) | them[1];
>     if (sizeof (unsigned long) > 2) result = (result << CHAR_BIT) | them[2];
>     if (sizeof (unsigned long) > 3) result = (result << CHAR_BIT) | them[3];
>     if (sizeof (unsigned long) > 4) result = (result << CHAR_BIT) | them[4];
>     if (sizeof (unsigned long) > 5) result = (result << CHAR_BIT) | them[5];
>     if (sizeof (unsigned long) > 6) result = (result << CHAR_BIT) | them[6];
>     if (sizeof (unsigned long) > 7) result = (result << CHAR_BIT) | them[7];
>     return result;
>     }

> So long as sizeof(unsigned long) <= 8, which covers all the machines I
> dare think about, this does it portably and with no loops. If your compiler
> won't optimise away the sizeof tests, either turn up the optimisation
> level a tad or get a better compiler.

> Critiques requested.

Adding a while loop after the last if could catch really humungous ul's,
at the expense of one redundant test on the more 'normal' architectures.

--

"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton

Mon, 26 Jan 2004 19:50:55 GMT
Convert four chars to a long and a long to four chars

Quote:

>> I'm piggybacking, rather than responding to Richard. A bit of experimenting
>> sugested this:

>> static unsigned long charsToLong( unsigned char *them )
>>     {
>>     register unsigned long result = 0;
>>     if (sizeof (unsigned long) > 0) result = (result << CHAR_BIT) | them[0];
>>     if (sizeof (unsigned long) > 1) result = (result << CHAR_BIT) | them[1];
>>     if (sizeof (unsigned long) > 2) result = (result << CHAR_BIT) | them[2];
>>     if (sizeof (unsigned long) > 3) result = (result << CHAR_BIT) | them[3];
>>     if (sizeof (unsigned long) > 4) result = (result << CHAR_BIT) | them[4];
>>     if (sizeof (unsigned long) > 5) result = (result << CHAR_BIT) | them[5];
>>     if (sizeof (unsigned long) > 6) result = (result << CHAR_BIT) | them[6];
>>     if (sizeof (unsigned long) > 7) result = (result << CHAR_BIT) | them[7];
>>     return result;
>>     }

>> So long as sizeof(unsigned long) <= 8, which covers all the machines I
>> dare think about, this does it portably and with no loops. If your compiler
>> won't optimise away the sizeof tests, either turn up the optimisation
>> level a tad or get a better compiler.

>> Critiques requested.

> Adding a while loop after the last if could catch really humungous ul's,
> at the expense of one redundant test on the more 'normal' architectures.

Like:

if (sizeof (unsigned long) > 8)
{
size_t count = sizeof (unsigned long) - 8;
int index = 8;
while (count--) result = (result << CHAR_BIT) | them[index++];
}

??

--
Chris "electric hedgehog" Dollin
C FAQs at: http://www.faqs.org/faqs/by-newsgroup/comp/comp.lang.c.html

Mon, 26 Jan 2004 19:58:53 GMT
Convert four chars to a long and a long to four chars

Quote:

> Is the high byte of thelong, thechars[0] or thechars[3]?

If it doesn't matter (though I suspect it does)
then this would be the fatsest way:

/* BEGIN new.txt */

thelong = 0XAABBCCDD;
The intial value of thelong is AABBCCDD

*(long*)thechars = thelong;
thechars[0] DD
thechars[1] CC
thechars[2] BB
thechars[3] AA

theotherlong = *(long*)thechars;
The value of the other long is AABBCCDD

/* END new.txt */

/* BEGIN new.c */

#include <stdio.h>
#include <stdlib.h>

#define thechars (tchars.tchar)

int main(void)
{
long thelong, theotherlong;
union{
long lin;
unsigned char tchar[sizeof(long)];
}tchars;
size_t index;
char *fn = "new.txt";
FILE *fp = fopen(fn, "wt");

if(!fp){
fprintf(stderr, "fopen(%s) error\n", fn);
exit(EXIT_FAILURE);
}
fprintf(fp, "/* BEGIN %s */\n\n", fn);
thelong = 0XAABBCCDD;
fprintf(fp, "thelong = 0XAABBCCDD;\n");
fprintf(fp, "The intial value of thelong is %X\n\n", thelong);
*(long*)thechars = thelong;
fprintf(fp, "*(long*)thechars = thelong;\n");
for (index = 0; index != sizeof(long); ++index)
fprintf(fp, "thechars[%lu] %X\n",
(unsigned long)index, thechars[index]);
theotherlong = *(long*)thechars;
fprintf(fp, "\ntheotherlong = *(long*)thechars;\n");
fprintf(fp, "The value of the other long is %X\n", theotherlong);
fprintf(fp, "\n/* END %s */\n", fn);
fclose(fp);
return 0;

Quote:
}

/*
btw, long = four bytes; char = 1 byte; in case thats platform specific)

what i want to do can be understood from this:
unsigned long thelong = 1002;
char thechars[4];

//how do i do this?
thechars = thelong

//and this
thelong = thechars

//replace the equals signs with an explanation please! :-)

thanks for all your help everyone
-joe
*/

/* END new.c */

--
pete

Mon, 26 Jan 2004 20:22:58 GMT
Convert four chars to a long and a long to four chars

: static unsigned long charsToLong( unsigned char *them )
:     {
:     register unsigned long result = 0;
:     if (sizeof (unsigned long) > 0) result = (result << CHAR_BIT) | them[0];
:     if (sizeof (unsigned long) > 1) result = (result << CHAR_BIT) | them[1];
:     if (sizeof (unsigned long) > 2) result = (result << CHAR_BIT) | them[2];
:     if (sizeof (unsigned long) > 3) result = (result << CHAR_BIT) | them[3];
:     if (sizeof (unsigned long) > 4) result = (result << CHAR_BIT) | them[4];
:     if (sizeof (unsigned long) > 5) result = (result << CHAR_BIT) | them[5];
:     if (sizeof (unsigned long) > 6) result = (result << CHAR_BIT) | them[6];
:     if (sizeof (unsigned long) > 7) result = (result << CHAR_BIT) | them[7];
:     return result;
:     }
:
: So long as sizeof(unsigned long) <= 8, which covers all the machines I
: dare think about, this does it portably and with no loops. If your compiler
: won't optimise away the sizeof tests, either turn up the optimisation
: level a tad or get a better compiler.

Well, if your compiler won't automatically unroll a loop with a small
constant number of iterations, either turn up the optimisation level a
tad or get a better compiler. :)

D:\>type catol.c
#include <limits.h>

unsigned long catol(const unsigned char *bp) {
int sz = sizeof(unsigned long);
unsigned long ul = 0;

do {
ul = (ul << CHAR_BIT) | *bp++;
} while (--sz);

return ul;

Quote:
}

D:\>uname -a
CYGWIN_NT-5.0 AVALON 1.3.2(0.39/3/2) 2001-05-20 23:28 i686 unknown

D:\>gcc --version
3.0

D:\>gcc -O3 -fomit-frame-pointer -funroll-loops catol.c -S

D:\>type catol.s
.file   "catol.c"
.text
.align 16
.globl _catol
.def    _catol; .scl    2;      .type   32;     .endef
_catol:
movl    4(%esp), %ecx
movzbl  (%ecx), %eax
movzbl  1(%ecx), %edx
sall    \$8, %eax
orl     %edx, %eax
movzbl  2(%ecx), %edx
sall    \$8, %eax
orl     %edx, %eax
movzbl  3(%ecx), %edx
sall    \$8, %eax
orl     %edx, %eax
ret

-- Mat.

Mon, 26 Jan 2004 21:04:55 GMT
Convert four chars to a long and a long to four chars

Quote:

> >> Critiques requested.

> > Adding a while loop after the last if could catch really humungous ul's,
> > at the expense of one redundant test on the more 'normal' architectures.

> Like:

>     if (sizeof (unsigned long) > 8)
>         {
>         size_t count = sizeof (unsigned long) - 8;
>         int index = 8;
>         while (count--) result = (result << CHAR_BIT) | them[index++];
>         }

> ??

Yes, exactly like that. :-)

--

"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton

Mon, 26 Jan 2004 21:01:08 GMT
Convert four chars to a long and a long to four chars

Quote:

>     long thelong, theotherlong;
>     fprintf(fp, "The intial value of thelong is %X\n\n", thelong);
>         fprintf(fp, "thechars[%lu] %X\n",
>         (unsigned long)index, thechars[index]);
>     fprintf(fp, "The value of the other long is %X\n", theotherlong);

For the benefit of fprintf, those lines should be changed to:

long unsigned thelong, theotherlong;

fprintf(fp, "The intial value of thelong is %lX\n\n", thelong);

fprintf(fp, "thechars[%lu] %X\n",
(long unsigned)index, (unsigned)thechars[index]);

fprintf(fp, "The value of the other long is %lX\n", theotherlong);

--
pete

Mon, 26 Jan 2004 21:02:39 GMT

 Page 1 of 2 [ 24 post ] Go to page: [1] [2]

Relevant Pages