In Part 1, I chose unsigned int as the type to use for displaying the bits of a value. The same general procedure can be done with other types as well. The biggest issue really is the expression which generates the most significant bit, for which there are a number of ways. Also, these snippets output to a string rather than print directly to the stdout. (Continued in Part 3.)

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

char *bits_uchar(char *dest, unsigned char d)
{
   char *start = dest;
   unsigned char bit;
   for ( bit = 1 << (CHAR_BIT - 1); bit > 0; bit >>= 1 )
   {
      *dest++ = d & bit ? '1' : '0';
   }
   *dest = 0;
   return start;
}

char *bits_ushort(char *dest, unsigned short d)
{
   char *start = dest;
   unsigned short bit;
   for ( bit = (((unsigned short)-1) >> 1) + 1; bit > 0; bit >>= 1 )
   {
      *dest++ = d & bit ? '1' : '0';
   }
   *dest = 0;
   return start;
}

char *bits_uint(char *dest, unsigned int d)
{
   char *start = dest;
   unsigned int bit;
   for ( bit = (-1U >> 1) + 1; bit > 0; bit >>= 1 )
   {
      *dest++ = d & bit ? '1' : '0';
   }
   *dest = 0;
   return start;
}

char *bits_ulong(char *dest, unsigned long d)
{
   char *start = dest;
   unsigned long bit;
   for ( bit = ULONG_MAX / 2 + 1; bit > 0; bit >>= 1 )
   {
      *dest++ = d & bit ? '1' : '0';
   }
   *dest = 0;
   return start;
}

char *bits_block(char *dest, const void *object, size_t size)
{
   char *start = dest;
   const unsigned char *byte;
   for ( byte = object; size-- > 0; ++byte )
   {
      bits_uchar(dest, *byte);
      dest += CHAR_BIT;
      *dest++ = size > 0 ? '-' : 0;
   }
   return start;
}

int main(void)
{
   char result[80];

   unsigned char  uc = 0x5A;
   unsigned short uh = 0x1234;
   unsigned int   ui = 0xABCD;
   unsigned long  ul = 0xDEADBEEF;
   double d = 123.456;

   printf("0x%-8X = \"%s\"\n",  uc, bits_uchar  (result, uc) );
   printf("0x%-8hX = \"%s\"\n", uh, bits_ushort (result, uh) );
   printf("0x%-8X = \"%s\"\n",  ui, bits_uint   (result, ui) );
   printf("0x%-8lX = \"%s\"\n", ul, bits_ulong  (result, ul) );
   printf("0x%-8lX = \"%s\"\n", ul, bits_block(result, &ul, sizeof ul) );
   printf("%-10g = \"%s\"\n",   d,  bits_block(result, &d,  sizeof  d) );

   return 0;
}

/* my output
0x5A       = "01011010"
0x1234     = "0001001000110100"
0xABCD     = "00000000000000001010101111001101"
0xDEADBEEF = "11011110101011011011111011101111"
0xDEADBEEF = "11101111-10111110-10101101-11011110"
123.456    = "01110111-10111110-10011111-00011010-00101111-11011101-01011110-01000000"
*/
The article starter has earned a lot of community kudos, and such articles offer a bounty for quality replies.