From: tombaker@world.std.com (Tom A Baker)
Subject: BINARY - Constants and conversions for base two.
Keywords: C binary conversion
Organization: Me, at The World Public Access UNIX, Brookline, MA
Date: Sat, 7 Nov 1992 03:50:24 GMT


A lot of very elegant code has been posted on this particular
topic since that guy asked about it this week.  I'm posting this
because it has been useful to me.  Of course, it is nowhere
near as clean but ... it works, so what can I say?

---------------------------------------------------------------
BINARY.H and BIN_RTNS.C

As I said in my posting this morning, I recently had to do some
fiddling with Forward Error Correction Codes; this meant
reading and examining and writing bit patterns a lot.  So
I threw this stuff together.

I know it's a quick-and-dirty thing, but it does the job.  If
you don't like it, fix it.  My personal opionion is that binary 
is something that I use so seldom, that I'm  not going to sink
any more effort into it 'til I need it.  Some of the more kludgy
stuff is there to work with non-standard compilers.

Okay.

---------------------------------------------------------------

    BINARY.H

Place the '.h' file into a directory which your compiler can
get to when it needs it.  If you need binary constants, add the
'#include "binary.h"' command to your program.

The constants 'b0000' through 'b1111' are obvious.  They're
defined as (long) and they work pretty transparently.

The way to use the B4(), B8(), ... B32() macros is also
obvious, given the examples in the file 'testpgm.c'  What
is NOT obvious is the "trick" mentioned therein.

In Ansi C, if I take the letter 'b' and the four digits
"0101" and write 'b##0101', the preprocessor will
concatenate that into the token 'b0101'.  And you see that
is defined as '(5)'.

If you are using an older compiler, like a lot of Unix
compilers, then edit the file so you take the letter 'b' and
the four digits "0101" and write it as 'b/**/0101'.  The
older compilers will remove the comment, leaving 'b0101' and
... et cetera.

---------------------------------------------------------------

    BIN_RTNS.C

Okay.

long SBTOL(char *) - A string of the form "[0[b]][01]*" to
integer.  Strings might be "1", "b1111", or "0b11011011011".

double SBTOD(char *) - Same thing, "[0[b]][01]*[.[01]*]", to
double.  Yes, you might want fractional binary.  So "0b1.1"
is one and a half, and "pi" is "11.0010010000111111011".  See
program "grope.c".

char *bltos(long) - Convert any integer to a string.  Yes, I use
an intermediate, octal string.  Yes, I use a static 100-byte
buffer for it, and another static 300-byte buffer for the
return value; when you've ported into yet another non-standard
memory allocation library, you're content to use an array for
small jobs.   Anyway, this does work.

---------------------------------------------------------------

pleasenoflames: If you want to roll your own, go ahead.  I
never said this was anything other than a useful quicky for
me; I just have a nack for keeping my routines 'general' and
therefore applicable to more than one situation.

This software is released to the public domain.  Please don't
sell it for a million dollars profit without giving me some.
I know where you live.

If you improve this program, please send me a copy.
tombaker@world.std.com || tabaker@aol.com || BIX as tombaker  
November 6, 1992
---------------------------------------------------------------


Note:  I took a cue from the preprocessor, which is supposed to
       do all arithmetic in (long) integers; all these constants
       are (long), and most times that will be transparent to
       (int) arithmetic.  But the "testpgm.c" example shows a
       way to get mistakes if you aren't watchful.

Note: This forces you to use four bits at a time, because it is all
      based on defining constants with four bits, named "b1001" and
      "b0000", for instance.  If you want to implement the shorter
      names, from "b0" on up to "b111", go ahead (there are only 14
      of them).  If you want to generate the macros for manipulating
      groups of three bits instead (if you think in octal), go ahead.

      Just don't go overboard; an earlier version did 8 bits, with
      256 constants.  That is a bit much for some preprocessors,
      considering how rarely any appreciable fraction of the constants
      are ever used.

--------------------- CHAINSAW HERE ---------------------------
/*- binary.h */
/*  1992 - Thomas A. Baker. */

#ifndef _BINARY_H_
#define _BINARY_H_

#define b0000 (0L)
#define b0001 (1L)
#define b0010 (2L)
#define b0011 (3L)
#define b0100 (4L)
#define b0101 (5L)
#define b0110 (6L)
#define b0111 (7L)
#define b1000 (8L)
#define b1001 (9L)
#define b1010 (10L)
#define b1011 (11L)
#define b1100 (12L)
#define b1101 (13L)
#define b1110 (14L)
#define b1111 (15L)

#define  B4(a)               (  b##a                       )
/* Older compilers use the "comment trick".  Get rid of the above line,
   then uncomment the following line and change the plusses to stars.
   #define B4(a) (b/++/a)
*/

#define  B8(a,i)             (( B4(a)            <<4L)|B4(i))
#define B12(a,i,c)           (( B8(a,i)          <<4L)|B4(c))
#define B16(a,i,c,d)         ((B12(a,i,c)        <<4L)|B4(d))
#define B20(a,i,c,d,e)       ((B16(a,i,c,d)      <<4L)|B4(e))
#define B24(a,i,c,d,e,f)     ((B20(a,i,c,d,e)    <<4L)|B4(f))
#define B28(a,i,c,d,e,f,g)   ((B24(a,i,c,d,e,f)  <<4L)|B4(g))
#define B32(a,i,c,d,e,f,g,h) ((B28(a,i,c,d,e,f,g)<<4L)|B4(h))

long   sbtol();
double sbtod();
char  *bltos();

#endif  _BINARY_H_
--------------------- CHAINSAW HERE ---------------------------
/*- bin_rtns.c - Convert binary strings to and from numeric variables. */
/*  1992 - Thomas A. Baker. */

char buffer[101];
char return_value[301];

/*-   long SBTOL(char *) - "[0[b]][01]*" to integer. */
long
sbtol(sb)
char *sb;
{
    long return_value = 0L;

    if( *sb != '\0' )
    {
        if( sb[0] == '0' && sb[1] == 'b' ) sb++;
        if( sb[0] == 'b')                  sb++;

        while( *sb && *sb>='0' && *sb<='1' )
        {
            return_value <<= 1;
            return_value  += (long)(*sb & 1);
            sb++;
        }
    }
    return return_value;
}

/*-   double SBTOD(char *) - "[0[b]][01]*[.[01]*]" to double. */
double
sbtod(sb)
char *sb;
{
    double return_value = (double) 0.0;
    double fraction     = (double) 1.0;

    if( *sb != '\0' )
    {
        if( sb[0] == '0' && sb[1] == 'b' ) sb++;
        if( sb[0] == 'b')                  sb++;

        while( *sb>='0' && *sb<='1' )
        {
            return_value *= 2.0;
            return_value += (double)(*sb & 1);
            sb++;
        }
        if( *sb == '.' )
        {
            sb++;
            fraction = (double) 1.0;
            while( *sb>='0' && *sb<='1' )
            {
                fraction /= (double) 2.0;
                if( *sb & 1 )
                    return_value += fraction;
                sb++;
            }
        }
    }
    return return_value;
}

/*-   char *BLTOS(long) - Long to binary string. */
char *
bltos( b )
long  b;
{
    char *p;

    sprintf( buffer, "%o", b );
    p = &buffer[0];
    strcpy( return_value, "" );
    while( *p=='0')
        p++;
    while( *p>='0' && *p<='7' )
    {
        if( *p & 4 )
            strcat( return_value, "1" );
        else
            strcat( return_value, "0" );
        if( *p & 2 )
            strcat( return_value, "1" );
        else
            strcat( return_value, "0" );
        if( *p & 1 )
            strcat( return_value, "1" );
        else
            strcat( return_value, "0" );
        p++;
    }
    p = &return_value[0];
    while( *p == '0' )
        p++;
    if( *p != '1' )
    {
        p = &return_value[0];
        strcpy( return_value, "0" );
    }
    return p;
}

#ifdef TESTING
main()
{
    long value;
    double fvalue;
    for(;;)
    {
        printf("L?");
        gets(buffer);
        value = sbtol(buffer);
        printf("          %ld\n", value);
        printf("          %s\n",  bltos(value));
        printf("F?");
        gets(buffer);
        fvalue = sbtod(buffer);
        printf("          %lf\n", fvalue);
        value = (long) fvalue;
        printf("          %s\n",  bltos(value));
    }
}
#endif TESTING
--------------------- CHAINSAW HERE ---------------------------
/*- testpgm.c */
/*  1992 - Thomas A. Baker. */

#include "binary.h"

main()
{
  printf("I'm %d years old.\n",  B8(0010,0111) );
  printf("One 'K' is %d.\n",    B12(0100,0000,0000) );
  printf("The year is %d.\n",   B12(0111,1100,1000) );
  printf("Minus one is %d.\n",  B16(1111,1111,1111,1111));
  printf("Minus one is %d.\n",  B32(1111,1111,1111,1111,1111,1111,1111,1111));
  printf("Minus one is %ld.\n", B32(1111,1111,1111,1111,1111,1111,1111,1111));
  printf("-100,000 ISN'T %d.\n",B32(1111,1111,1111,1110,0111,1001,0110,0000));
  printf("-100,000  is  %ld.\n",B32(1111,1111,1111,1110,0111,1001,0110,0000));
  return B4(0000);
}
--------------------- CHAINSAW HERE ---------------------------
/*- grope.c */
/*  1992 - Thomas A. Baker. */

#include "binary.h"

main()
{
    char buffer[100];

    while(1)
    {
        gets(buffer);
        printf("%lf\n", sbtod(buffer));
    }
}
--------------------- CHAINSAW HERE ---------------------------
End of Post