Anyone mind reviewing my code?

  • Thread starter Mantorok Redgormor
  • Start date
M

Mantorok Redgormor

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

int main(void)
{
unsigned int mask;
int a = -1;
mask = 1u << (CHAR_BIT * sizeof mask - 1);


while(mask) {
putchar(a & mask ? '1' : '0');
mask>>=1u;
}

putchar('\n');

return 0;
}

I was wanting to display the underlying representation
of signed and unsigned integers. I don't think I am
invoking undefined behavior but if I am, could someone
point it out?

Also, I can only use integer types with bitwise AND
And this is a convenient way of testing against
a mask. So how would one determine the bits
set in a float or double type to display the
underlying representation in binary?

I thought about using the examples from a
previously similar question I asked.
Where the examples given displayed the bytes in hex
I was thinking maybe I could display each individual
byte by displaying those bytes in binary consecutively.
But maybe there is a more clever way?
 
A

Arthur J. O'Dwyer

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

int main(void)
{
unsigned int mask;
int a = -1;
mask = 1u << (CHAR_BIT * sizeof mask - 1);

Undefined behavior if 'unsigned int' has any
padding bits, I think. At best, it's
implementation-defined behavior.

I believe

mask = ~0u ^ (~0u >> 1)

is guaranteed correct, although I could be
mistaken. In general, this kind of bit-twiddling
is highly representation-specific, since who
in their right minds would write bit-twiddling
code like this that *needed* to run on two different
architectures?
while(mask) {
putchar(a & mask ? '1' : '0');
mask>>=1u;
}

It would be even more portable to forget the bit
twiddling entirely, and use a recursive approach:

void print_bits(unsigned int x)
{
if (x != 0) print_bits(x/2);
printf("%d", x&1);
}


print_bits(a);

Exercise: Modify the above function to take an argument
saying how many bits to print in all.
putchar('\n');

return 0;
}

Also, I can only use integer types with bitwise AND
And this is a convenient way of testing against
a mask. So how would one determine the bits
set in a float or double type to display the
underlying representation in binary?

Examine it as an array of 'unsigned char':

double real = 3.141593;
unsigned char *representation = (unsigned char *)&real;
...
I thought about using the examples from a
previously similar question I asked.
Where the examples given displayed the bytes in hex
I was thinking maybe I could display each individual
byte by displaying those bytes in binary consecutively.
But maybe there is a more clever way?

Nope. :)

-Arthur
 
P

Peter Nilsson

Arthur J. O'Dwyer said:
Undefined behavior if 'unsigned int' has any
padding bits, I think.
Correct.

At best, it's implementation-defined behavior.

I believe

mask = ~0u ^ (~0u >> 1)

I'm partial to...

mask = -1u/2+1;
is guaranteed correct, although I could be
mistaken. In general, this kind of bit-twiddling
is highly representation-specific,

How many variant representations for unsigned types do you think there
are? As far as the value bits are concerned, there is only one, 'pure
binary'.
since who
in their right minds would write bit-twiddling
code like this that *needed* to run on two different
architectures?

People implementing portable encryption or coding theory algorithms
for one.

But, dumping bit-sets in most to least-significant order is not that
uncommon, or at least, I wouldn't have thought so.
 
A

Arthur J. O'Dwyer

[Something else...]
How many variant representations for unsigned types do you think there
are? As far as the value bits are concerned, there is only one, 'pure
binary'.

True. I had forgotten for a moment we were talking unsigned.
However, the numbers of value bits and padding bits are still
part of the implementation-defined representation.
People implementing portable encryption or coding theory algorithms
for one.

While you may have a point, I think far more encryption schemes
will *assume* 32-bit 'int' or 8-bit 'char', and work with those.
Also, real code does not resort to weird bit-twiddling hacks to
produce values like 0x80000000; you'd simply write that value,
if that's what you meant. Or parameterize your coding algorithm
to specify the width of the data type being coded.
But, dumping bit-sets in most to least-significant order is not that
uncommon, or at least, I wouldn't have thought so.

True. That's why I gave the _portable_, recursive,
non-bit-twiddling solution.

-Arthur
 
D

Dave Thompson

I was wanting to display the underlying representation
of signed and unsigned integers. I don't think I am
invoking undefined behavior but if I am, could someone
point it out?
</>
Note that none of these really display the underlying representation.
Where they work at all they display the value bits of the unsigned
value, which are (by requirement) much though possibly not all of the
representation; or of the signed value converted to unsigned, which
need not be so, although on two's-complement systems, the overwhelming
majority by far today, they are.
Undefined behavior if 'unsigned int' has any
padding bits, I think. At best, it's
implementation-defined behavior.
Not undefined. Shifts, like all other arithmetic operations, on
unsigned (integer) types, are well-defined. In this case, if there
are padding bits, which is i-d, the computed value will be reduced
modulo (UINT_MAX+1) to zero, which is useless.
I believe

mask = ~0u ^ (~0u >> 1)

is guaranteed correct, although I could be
mistaken. In general, this kind of bit-twiddling
is highly representation-specific, since who
in their right minds would write bit-twiddling
code like this that *needed* to run on two different
architectures?
If you really did look at the representation, that is one type,
perhaps the only type, of bit twiddling where you would have a real
need to run on different platforms.
It would be even more portable to forget the bit
twiddling entirely, and use a recursive approach:

void print_bits(unsigned int x)
{
if (x != 0) print_bits(x/2);
printf("%d", x&1);
}
Or x%2 to avoid the bitwise operators altogether and be symmetric with
/, although for unsigned types and a power of two any decent compiler
on any non-brain-damaged platform will still implement as bit ops.

And more direct and probably more efficient, putchar( x%2 +'0').

Examine it as an array of 'unsigned char':

double real = 3.141593;
unsigned char *representation = (unsigned char *)&real;
...
Right.

- David.Thompson1 at worldnet.att.net
 
P

Peter Nilsson

Dave Thompson said:
Not undefined. Shifts, like all other arithmetic operations, on
unsigned (integer) types, are well-defined. In this case, if there
are padding bits, which is i-d, the computed value will be reduced
modulo (UINT_MAX+1) to zero, which is useless.

Sorry Dave, you missed the first semantic paragraph...

Bitwise shift operators
...
The integral promotions are performed on each of the operands. The
type of the result is that of the promoted left operand. If the value
of the right operand is negative or is greater than or equal to the
width in bits of the promoted left operand, the behavior is undefined.

Note the term 'width' is defined earlier as sign + value bits.
 
D

Dave Thompson

Sorry Dave, you missed the first semantic paragraph... <snip>

Argh! I didn't miss it, I just forgot it. Sorry.

- David.Thompson1 at worldnet.att.net
 

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

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top