Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Portability question

243 views
Skip to first unread message

Stephen Mayes

unread,
Dec 30, 2003, 11:58:51 AM12/30/03
to
Please humor a curious hobbyist.

Below is some code I made to amuse myself and reverse bit order. Any
comments or corrections are welcome, but I have some specific concerns.
I added the #define to try to make this portable. But what if I wanted to
*ensure* that my data type had 32 bits?
Would this be done in pre-processing?
If the 32-bit type turns out *not* to be unsigned long, how could I declare
p and r, and wouldn't my printf's and scanf be in trouble, too?
Are my concerns completely unfounded? Is there ever any valid reason to
*ensure* a specific bit count?
I really don't know where to begin, so a hint or a pointer to some relevant
example might be more fun that actually telling.

gcc -ansi -pedantic -lm rev.c
cat rev.c

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <limits.h>

#define LONG_BIT (CHAR_BIT * sizeof(unsigned long))

void print_binary( unsigned long n )
{
int i = 0;

for ( i = LONG_BIT - 1; i >= 0; i-- )
putchar( n & 1 << i ? '1' : '0' );
printf( "\n" );
}

int main( void )
{
unsigned long p = 0, r = 0;
int i;

for(;;)
{
p = pow( 2, LONG_BIT ) - 1;
r = 0;

printf( "\nEnter an integer value 0 to %lu or 'q' to
quit\n",
p );
if ( ! scanf( "%lu", &p ) )
{
if ( toupper( getchar() ) == 'Q' )
break;
puts( "Input error." );
while ( getchar() != '\n' );
continue;
}
while ( getchar() != '\n' );

for ( i = 0; i < LONG_BIT; i++ )
{
if ( p & ( 1 << i ) )
r |= ( 1 << ( LONG_BIT - 1 - i ) );
}

printf( "Value: %lu\n", p );
printf( "%-10s", "Binary:" );
print_binary( p );
printf( "%-10s", "Reversed:" );
print_binary( r );
}
return EXIT_SUCCESS;
}


Hallvard B Furuseth

unread,
Dec 30, 2003, 12:38:30 PM12/30/03
to
Stephen Mayes wrote:

> But what if I wanted to
> *ensure* that my data type had 32 bits?

I don't know why you are asking about 32 bits, since none of
your code contains any assumption of 32 bits. However,

You can only do that if there _is_ a 32-bit datatype...

If you use C99, you can use the <inttypes.h> header.
It #defines format specifiers for exact-width integer types
#defined in <stdint.h>, which it #includes.
It will declare the type uint32_t and #define the PRIu32 and SCNu32
macros with format specifiers if there is such a type.

Otherwise, you could use a type which has _at least_ 32 bits
(uint_least32_t and PRIuLEAST32, SCNuLEAST32), and remove unwanted bits
by hand (by doing 'value & 0xFFFFFFFFU').

> Would this be done in pre-processing?
> If the 32-bit type turns out *not* to be unsigned long, how could I
> declare p and r, and wouldn't my printf's and scanf be in trouble,
> too?

With C99, #ifdef PRIu32 or PRIuLEAST32 should get you there.
With older C versions, you can use

#include <limits.h>
#if UINT_MAX >= 0xFFFFFFFFUL
typedef unsigned int Uint32
# define UINT32_FMT ""
#else
typedef unsigned long Uint32
# define UINT32_FMT "l"
#endif

... printf("%" UINT32_FMT "u", some_Uint32_variable); ...

and, as I mentioned, mask away unwanted bits with '&'.

> Are my concerns completely unfounded? Is there ever any valid reason
> to *ensure* a specific bit count?

Sometimes. Usually it is enough to ensure 'at least X bits'.

> #define LONG_BIT (CHAR_BIT * sizeof(unsigned long))

This value is too large if unsigned long has padding bits (bits which do
not contribute to the value). You need to count the number of bits in
ULONG_MAX. The readable way to do that is with a loop. The preprocessor
way to do it is IMAX_BITS(ULONG_MAX), with the following macro:

/* Number of bits in inttype_MAX, or in any (1<<b)-1 where 0 <= b < 3E+10 */
#define IMAX_BITS(m) ((m) /((m)%0x3fffffffL+1) /0x3fffffffL %0x3fffffffL *30 \
+ (m)%0x3fffffffL /((m)%31+1)/31%31*5 + 4-12/((m)%31+3))

IMAX_BITS(INT_MAX) computes the number of bits in an int, and
IMAX_BITS((unsigned_type)-1) computes the number of bits in an
unsigned_type. Until someone implements 4-gigabyte integers, anyway:-)

Explanation, where 'x**y' means x raised to the power of y:
Line 1 computes (number of whole 30-bit chunks) * 30:
For m = (2**(K*n+r))-1 and P = (2**K)-1 with K=30, P=0x3fffffff,
m = (P+1)**n * 2**r - 1,
m % P + 1 = 1 * 2**r - 1 + 1 = 2**r when 2**r-1<P so r<K,
m /(m%P+1) = (P+1)**n - 1
= ((P+1)-1) * ((P+1)**0 +...+ (P+1)**(n-1)),
.../P%P*K = ( 1**0 +...+ 1**(n-1)) % P * K
= n*K when n < P.
Part 2 does the same to the remainder (m%0x3fffffff) with K=5, P=31.
Part 3 "happens" to count the final 0-4 bits in m%31=[0/1/3/7/15].
m % 31 is short for m % 0x3fffffff % 31, because 0x3fffffff % 31 = 0.
0x3fffffffL is the largest portable 2**x-1 with such a 2**y-1 factor.

> for ( i = LONG_BIT - 1; i >= 0; i-- )
> putchar( n & 1 << i ? '1' : '0' );

1 << i should be 1UL << i or (some_wide_enough_unsigned_type)1 << i,
otherwise it will overflow if i < (number of bits in an int), or - since
you used a signed constant (1), if the 1 is shifted into the sign bit.

> p = pow( 2, LONG_BIT ) - 1;

Since pow() is a floating-point function, the result is inaccurate.
Use ULONG_MAX or (unsigned long)-1.

If you wanted exactly 32 bits but use an integer type which may
be wider than that, I think you would need something like

((1UL << (LONG_BIT -1)) - 1) * 2 - 1

> if ( ! scanf( "%lu", &p ) )

If you type Return, this will just keep waiting for you to type in a
number, since scanf(%lu) ignores preceding whitespace. I don't know if
that is what you want or not. If not, read one line into an input
buffer with fgets() (NOT gets()!) and use sscanf() to read the integer
from that buffer.

> while ( getchar() != '\n' );

This will loop forever if you reach the end of the file.

int ch;
while ((ch = getchar()) != EOF && ch != '\n');


> for ( i = 0; i < LONG_BIT; i++ )
> {
> if ( p & ( 1 << i ) )
> r |= ( 1 << ( LONG_BIT - 1 - i ) );

Again, shift 1UL, not 1.

--
Hallvard

CBFalconer

unread,
Dec 30, 2003, 3:05:11 PM12/30/03
to
Hallvard B Furuseth wrote:
> Stephen Mayes wrote:
>
> > But what if I wanted to
> > *ensure* that my data type had 32 bits?
>
> I don't know why you are asking about 32 bits, since none of
> your code contains any assumption of 32 bits. However,
>
> You can only do that if there _is_ a 32-bit datatype...

unsigned long and long are guaranteed to be at least 32 bits.
Thus they can always hold a 32 bit type. Unsigned versions will
not run into UB, barring division by zero, but the signed versions
will.

--
Chuck F (cbfal...@yahoo.com) (cbfal...@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!


Stephen Mayes

unread,
Dec 30, 2003, 8:56:29 PM12/30/03
to

"Hallvard B Furuseth" <h.b.furuseth(nospam)@usit.uio(nospam).no> wrote in
message news:HBF.2003...@bombur.uio.no...

> Stephen Mayes wrote:
>
> > But what if I wanted to
> > *ensure* that my data type had 32 bits?
>
> I don't know why you are asking about 32 bits, since none of
> your code contains any assumption of 32 bits. However,

Thanks for all the input.
I've been looking at rfc1321 about md5. Section 2 mentions circularly
shifting a 32-bit *word*. That's where my brain was. I wanted to practice
a little bit-manipulating.

> > Are my concerns completely unfounded? Is there ever any valid reason
> > to *ensure* a specific bit count?
>
> Sometimes. Usually it is enough to ensure 'at least X bits'.

I'm thinking that should be the case with md5. I probably wouldn't even
need to mask anything.
Thanks again.


pete

unread,
Dec 31, 2003, 7:30:48 AM12/31/03
to
Stephen Mayes wrote:
>
> Please humor a curious hobbyist.
>
> Below is some code I made to amuse myself and reverse bit order.
> Any comments or corrections are welcome,
> but I have some specific concerns.
> I added the #define to try to make this portable.
> But what if I wanted to *ensure* that my data type had 32 bits?

The simplest portable way to reverse the bits of an object
with an arbitrary number of bytes, of arbitrary width,
is to reverse the order of the bits of each byte,
and then reverse to order of the bytes.

rev_byte.c will reverse the order of bits, in bytes of any width:

http://groups.google.com/groups?selm=3F757E30.57CB%40mindspring.com

--
pete

Hallvard B Furuseth

unread,
Dec 31, 2003, 1:32:47 PM12/31/03
to
CBFalconer wrote:

> unsigned long and long are guaranteed to be at least 32 bits.

True. I assumed he meant _exactly_ 32 bits, or at least as
few bits more as necessary.

> Thus they can always hold a 32 bit type. Unsigned versions will
> not run into UB, barring division by zero, but the signed versions
> will.

Yup. Bit fiddling with signed numbers should be avoided.

--
Hallvard

0 new messages