4
\$\begingroup\$

I'm curious as to peoples thoughts on this small library I have made. I noticed there are no functions in the C standard library to accomplish this task.

I have tried to make the code machine independent. If anyone has access to machines where short != 2 byte, int != 4 byte, long != 8 byte or where bytes themselves are not 8 bits. I would be curious as to the test results.

GitHub

The current functions for printing the binary representations are all slight modifications of the below:

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

void printcb(char n)
{
    int i;
    int type_bits = CHAR_BIT;
    int mask = 1 << type_bits - 1;

    for (i = 0; i < type_bits; ++i) {
        if (n & mask)
            putc('1', stdout);
        else
            putc('0', stdout);
        n <<= 1;
    }
    putc('\n', stdout);
}
\$\endgroup\$
4
\$\begingroup\$

The left shift operator on signed types is tricky and will easily lead you to undefined behavior.

To put it formally, here is a quote from §6.5.7/4 Bitwise shift operators of a C11 draft, emphasis added:

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1 × 2E2 , reduced modulo one more than the maximum value representable in the result type. If E1 has a signed type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

char is signed on a lot of platforms (likely including on the one you're testing). Therefore the following expression can fall foul of the "non-negative" constraint in the standardese above:

n <<= 1;

If n is negative, the expression has undefined behavior, even on common platforms with boring 8-bit (signed) chars.


There's a problem with the following too, on stranger implementations, related to the second constraint:

int mask = 1 << type_bits - 1;

On a platform where sizeof(int) == sizeof(char) (possible with e.g. CHAR_BITS==16 implementations, see What platforms have something other than 8-bit char? for examples), that shift will push the 1 into the sign bit, which has undefined behavior: 1 x 2CHAR_BITS-1 is not representable (at least in 2's complement, 1's complement or sign/magnitude representations – they stop at 2CHAR_BITS-1-1. No idea if there are other representations that fulfill the C standard's conditions and would be able to represent that).


TLDR: unsigned types are the bit-twiddler's friend.

|improve this answer|||||
\$\endgroup\$
4
\$\begingroup\$
  • You can just call putchar(), which automatically prints to stdout:

    putchar('1');
    
  • The conditionals can instead be a ternary statement within putchar():

    putchar(n & mask ? '1' : '0');
    

putchar is often better suited for single-character output. putchar only has to pass a character directly to the output. This particular code isn't exactly performance-critical but it's useful to acquire good coding habits from the beginning.

|improve this answer|||||
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.