Portability question

S

Stephen Mayes

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;
}
 
H

Hallvard B Furuseth

Stephen said:
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.
 
C

CBFalconer

Hallvard said:
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.
 
S

Stephen Mayes

Hallvard B Furuseth said:
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.
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.
 
P

pete

Stephen said:
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/[email protected]
 
H

Hallvard B Furuseth

CBFalconer said:
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,129
Messages
2,570,770
Members
47,329
Latest member
FidelRauch

Latest Threads

Top