critique: conversion to binary

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • bowsayge

    critique: conversion to binary

    Inspired by fb, Bowsayge decided to write a decimal integer
    to binary string converter. Perhaps some of the experienced
    C programmers here can critique it. It allocates probably
    way too much memory, but it should certainly handle 64-bit
    cpus :)

    #include <stdio.h>
    #include <stdlib.h>

    char * to_binary (unsigned long value) {
    const int maxdata = 100;
    char * data = malloc(maxdata+ 1);
    int pos = 0;
    int pos2 = 0;
    if (0 == data) return 0;

    if (0 == value) {
    return strcpy (data, "0");
    }

    while (value > 0) {
    if (pos >= maxdata) {
    printf ("ran out of memory\n");
    exit(EXIT_FAILU RE);
    }
    data [pos++] = '0' + (value & 1);
    value >>= 1;
    }
    data[pos--] = 0;

    for (pos2 = 0; pos2 < pos; pos2++, pos--) {
    char temp = data[pos];
    data[pos] = data[pos2];
    data[pos2] = temp;
    }

    return data;
    }

    int main (int argc, const char * argv [])
    {
    int ii = 0;
    while (ii < argc) {
    unsigned long num = ii < 1 ? 5 : atol(argv[ii]);
    char * str = to_binary(num);

    if (0 == str) return EXIT_FAILURE;
    printf ("%lu (decimal) = %s (binary)\n", num, str);
    free(str);
    ii++;
    }
    return EXIT_SUCCESS;
    }

  • Turner, GS (Geoff)

    #2
    Re: critique: conversion to binary


    [color=blue]
    > -----Original Message-----
    > From: bowsayge [mailto:bowsayge @nomail.afraid. org]
    > Posted At: 03 September 2004 09:13
    > Posted To: c
    > Conversation: critique: conversion to binary
    > Subject: critique: conversion to binary
    >
    >
    > Inspired by fb, Bowsayge decided to write a decimal integer
    > to binary string converter. Perhaps some of the experienced
    > C programmers here can critique it. It allocates probably
    > way too much memory, but it should certainly handle 64-bit
    > cpus :)
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    >
    > char * to_binary (unsigned long value) {
    > const int maxdata = 100;
    > char * data = malloc(maxdata+ 1);
    > int pos = 0;
    > int pos2 = 0;
    > if (0 == data) return 0;
    >
    > if (0 == value) {
    > return strcpy (data, "0");
    > }
    >
    > while (value > 0) {
    > if (pos >= maxdata) {
    > printf ("ran out of memory\n");
    > exit(EXIT_FAILU RE);
    > }
    > data [pos++] = '0' + (value & 1);
    > value >>= 1;
    > }
    > data[pos--] = 0;
    >
    > for (pos2 = 0; pos2 < pos; pos2++, pos--) {
    > char temp = data[pos];
    > data[pos] = data[pos2];
    > data[pos2] = temp;
    > }
    >
    > return data;
    > }
    >
    > int main (int argc, const char * argv [])
    > {
    > int ii = 0;
    > while (ii < argc) {
    > unsigned long num = ii < 1 ? 5 : atol(argv[ii]);
    > char * str = to_binary(num);
    >
    > if (0 == str) return EXIT_FAILURE;
    > printf ("%lu (decimal) = %s (binary)\n", num, str);
    > free(str);
    > ii++;
    > }
    > return EXIT_SUCCESS;
    > }
    >[/color]

    The following works OK for me.

    #include <stdio.h>
    #include <string.h>

    void Bin2( char *buffer, long n)
    {
    buffer--;
    *buffer = (char) (n%2+'0');
    n=n/2;
    if (n)
    Bin2(buffer,n);
    }


    int main (void)
    {
    char strBin[]="00000000"; // or 16, 32 etc
    char *fred = strBin+strlen(s trBin);

    Bin2(fred,22);

    printf("%s\n",s trBin);

    return 0;
    }

    GST

    Comment

    • Rich Grise

      #3
      Re: critique: conversion to binary

      bowsayge wrote:
      [color=blue]
      > Inspired by fb, Bowsayge decided to write a decimal integer
      > to binary string converter. Perhaps some of the experienced
      > C programmers here can critique it. It allocates probably
      > way too much memory, but it should certainly handle 64-bit
      > cpus :)
      >
      > #include <stdio.h>
      > #include <stdlib.h>
      >
      > char * to_binary (unsigned long value) {
      > const int maxdata = 100;
      > char * data = malloc(maxdata+ 1);
      > int pos = 0;
      > int pos2 = 0;
      > if (0 == data) return 0;
      >
      > if (0 == value) {
      > return strcpy (data, "0");
      > }
      >
      > while (value > 0) {
      > if (pos >= maxdata) {
      > printf ("ran out of memory\n");
      > exit(EXIT_FAILU RE);
      > }
      > data [pos++] = '0' + (value & 1);
      > value >>= 1;
      > }
      > data[pos--] = 0;
      >
      > for (pos2 = 0; pos2 < pos; pos2++, pos--) {
      > char temp = data[pos];
      > data[pos] = data[pos2];
      > data[pos2] = temp;
      > }
      >
      > return data;
      > }
      >
      > int main (int argc, const char * argv [])
      > {
      > int ii = 0;
      > while (ii < argc) {
      > unsigned long num = ii < 1 ? 5 : atol(argv[ii]);
      > char * str = to_binary(num);
      >
      > if (0 == str) return EXIT_FAILURE;
      > printf ("%lu (decimal) = %s (binary)\n", num, str);
      > free(str);
      > ii++;
      > }
      > return EXIT_SUCCESS;
      > }[/color]

      Do you see the memory leak?

      It's also an awful lot of rigamarole - why not just allocate temp[] to write
      the bit digits to, then do data[pos++] = temp [pos2--]. You could also stack
      them.

      Cheers!
      Rich

      Comment

      • Does It Matter

        #4
        Re: critique: conversion to binary

        On Fri, 3 Sep 2004, bowsayge wrote:
        [color=blue]
        > Inspired by fb, Bowsayge decided to write a decimal integer
        > to binary string converter. Perhaps some of the experienced
        > C programmers here can critique it. It allocates probably
        > way too much memory, but it should certainly handle 64-bit
        > cpus :)[/color]

        Gak! K.I.S.S.

        The code below is unnecessarily complex. Keep it simple. The fact that
        something this simple takes more than 25 lines to do makes it harder to
        understand and maintain. A quick glance at this code and I don't
        immediately know what you are attempting to do.

        Additionally, allocate the amount of memory you need. Using <limits.h> you
        should be able to figure out how many bits (char in the array) you need to
        represent an unsigned long integer.
        [color=blue]
        > #include <stdio.h>
        > #include <stdlib.h>
        >
        > char * to_binary (unsigned long value) {
        > const int maxdata = 100;[/color]

        Try sizeof(value)*C HAR_BIT/3+1. This will be a little too many bytes but
        it is safer than a magic number like 100. What happens if this code goes
        into a 64-bit machine and years later gets recompiled on a 128 bit
        machine? You are only allocating 100 bits. Even if you allocate 512 bits
        you are just delaying the problem. I am sure there where people in the
        60's program 7 and 8 bit computers who would never imagine there would be
        64 bit computers. So they hard coded things for 50 bits.
        [color=blue]
        > char * data = malloc(maxdata+ 1);
        > int pos = 0;
        > int pos2 = 0;
        > if (0 == data) return 0;[/color]

        Just a style thing, I liked to use NULL == data rather than 0 == data.
        [color=blue]
        > if (0 == value) {
        > return strcpy (data, "0");
        > }[/color]

        Why the special case for zero? If you can write the code such that zero is
        no different from any other value, do it.
        [color=blue]
        > while (value > 0) {
        > if (pos >= maxdata) {
        > printf ("ran out of memory\n");
        > exit(EXIT_FAILU RE);
        > }[/color]

        It is good that you have some sort of test for exceeding the 100 bit
        limit. Unfortunately, you spent the time allocating 100 bytes and
        generating 100 bits of data for nothing. It would have been better for the
        code to attempt to allocate the correct amount and fail at the malloc.
        Less processing.

        Additionally, what happened to freeing the memory you allocated? You have
        a memory leak.

        Also, style issue. I call a utility program and it exits my entire
        application. I would not be happy with that. I would prefer this if
        statement free the memory and return a NULL pointer.
        [color=blue]
        > data [pos++] = '0' + (value & 1);
        > value >>= 1;
        > }
        > data[pos--] = 0;[/color]

        You appear to be creating the string backwards.
        [color=blue]
        > for (pos2 = 0; pos2 < pos; pos2++, pos--) {
        > char temp = data[pos];
        > data[pos] = data[pos2];
        > data[pos2] = temp;
        > }[/color]

        And this loop appears to be correcting the mistake. Did you program the
        code without this second loop, see the string was backwards and add the
        final for loop to correct the problem? I would have corrected the problem
        in the first loop.
        [color=blue]
        > return data;
        > }[/color]

        I created a solution. It is one if statement to see if the malloc failed,
        a for loop with one line in the body to create the string, an assignment
        after the for loop to end the string and a return statement. Even with
        white space, #include statements and the signature it is 18 lines.
        [color=blue]
        > int main (int argc, const char * argv [])
        > {
        > int ii = 0;
        > while (ii < argc) {
        > unsigned long num = ii < 1 ? 5 : atol(argv[ii]);
        > char * str = to_binary(num);
        >
        > if (0 == str) return EXIT_FAILURE;
        > printf ("%lu (decimal) = %s (binary)\n", num, str);
        > free(str);
        > ii++;
        > }
        > return EXIT_SUCCESS;
        > }[/color]

        Hard to see the code is working with this. Converting from hex to binary
        is easy. You might want to print out a hex/binary table. Additionally, why
        not just use a for loop and print out 0 to 128 then maybe some boundary
        cases. You will see an obvious pattern. If the code is wrong the pattern
        will be wrong as well.

        --
        Send e-mail to: darrell at cs dot toronto dot edu
        Don't send e-mail to vice.president@ whitehouse.gov

        Comment

        • John Smith

          #5
          Re: critique: conversion to binary

          >[color=blue][color=green]
          > > char * data = malloc(maxdata+ 1);
          > > int pos = 0;
          > > int pos2 = 0;
          > > if (0 == data) return 0;[/color]
          >
          > Just a style thing, I liked to use NULL == data rather than 0 == data.
          >[/color]

          Just a style thing: I prefer "data == NULL": What's with this fixation on
          writing if statements in reverse, just to catch a typo?


          Comment

          • Emmanuel Delahaye

            #6
            Re: critique: conversion to binary

            John Smith wrote on 03/09/04 :[color=blue][color=green][color=darkred]
            >>> if (0 == data) return 0;[/color]
            >>
            >> Just a style thing, I liked to use NULL == data rather than 0 == data.
            >>[/color]
            >
            > Just a style thing: I prefer "data == NULL": What's with this fixation on
            > writing if statements in reverse, just to catch a typo?[/color]

            Yes. I'm not found of it, but it can help sometimes.

            --
            Emmanuel
            The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
            The C-library: http://www.dinkumware.com/refxc.html

            "C is a sharp tool"

            Comment

            • CBFalconer

              #7
              Re: critique: conversion to binary

              John Smith wrote:[color=blue]
              >[color=green]
              > >[color=darkred]
              > > > char * data = malloc(maxdata+ 1);
              > > > int pos = 0;
              > > > int pos2 = 0;
              > > > if (0 == data) return 0;[/color]
              > >
              > > Just a style thing, I liked to use NULL == data rather than 0 == data.
              > >[/color]
              >
              > Just a style thing: I prefer "data == NULL": What's with this fixation on
              > writing if statements in reverse, just to catch a typo?[/color]

              Just to catch a typo :-)

              --
              "A man who is right every time is not likely to do very much."
              -- Francis Crick, co-discover of DNA
              "There is nothing more amazing than stupidity in action."
              -- Thomas Matthews


              Comment

              • bowsayge

                #8
                Re: critique: conversion to binary

                Turner, GS (Geoff) said to us:
                [color=blue]
                > The following works OK for me.
                >
                > void Bin2( char *buffer, long n)[/color]
                [...]

                Yours is a lot more compact. Thanks.

                Comment

                • bowsayge

                  #9
                  Re: critique: conversion to binary

                  Rich Grise said to us:
                  [color=blue]
                  > bowsayge wrote:
                  >[color=green]
                  >> while (ii < argc) {
                  >> unsigned long num = ii < 1 ? 5 : atol(argv[ii]);
                  >> char * str = to_binary(num);
                  >>
                  >> if (0 == str) return EXIT_FAILURE;
                  >> printf ("%lu (decimal) = %s (binary)\n", num, str);
                  >> free(str);
                  >> ii++;
                  >> }[/color]
                  >
                  > Do you see the memory leak?[/color]

                  No, the "free (str)" above releases the memory.
                  [color=blue]
                  >
                  > It's also an awful lot of rigamarole - why not just allocate temp[] to
                  > write the bit digits to, then do data[pos++] = temp [pos2--].
                  > You could also stack them.[/color]

                  Yes! That'll eliminate the need to reverse the string. Thanks.

                  Comment

                  • CBFalconer

                    #10
                    Re: critique: conversion to binary

                    bowsayge wrote:[color=blue]
                    > Rich Grise said to us:
                    >[/color]
                    .... snip ...[color=blue][color=green]
                    >>
                    >> It's also an awful lot of rigamarole - why not just allocate
                    >> temp[] to write the bit digits to, then do
                    >> data[pos++] = temp[pos2--]. You could also stack them.[/color]
                    >
                    > Yes! That'll eliminate the need to reverse the string. Thanks.[/color]

                    Nothing wrong with reversing strings. A routine to do so is short
                    and quite efficient, and useful elsewhere. Now that you have
                    beaten this to death take a look at the following (which I have
                    published before). Only the first 80 odd lines are generically
                    useful, the rest is stuff to exercise it and convince oneself that
                    it works correctly.

                    /* Routines to display values in various bases */
                    /* with some useful helper routines. */
                    /* by C.B. Falconer, 19 Sept. 2001 */
                    /* Released to public domain. Attribution appreciated */

                    #include <stdio.h>
                    #include <string.h>
                    #include <limits.h> /* ULONG_MAX etc. */

                    /* =============== ======== */
                    /* reverse string in place */
                    size_t revstring(char *stg)
                    {
                    char *last, temp;
                    size_t lgh;

                    lgh = strlen(stg);
                    if (lgh > 1) {
                    last = stg + lgh; /* points to '\0' */
                    while (last-- > stg) {
                    temp = *stg; *stg++ = *last; *last = temp;
                    }
                    }
                    return lgh;
                    } /* revstring */

                    /* =============== =============== ============== */
                    /* Mask and convert digit to hex representation */
                    /* Output range is 0..9 and a..f only */
                    int hexify(unsigned int value)
                    {
                    static char hexchars[] = "0123456789abcd ef";

                    return (hexchars[value & 0xf]);
                    } /* hexify */

                    /* =============== =============== =============== ===== */
                    /* convert unsigned number to string in various bases */
                    /* 2 <= base <= 16, controlled by hexify() */
                    /* Returns actual output string length */
                    size_t basedisplay(uns igned long number, unsigned int base,
                    char *stg, size_t maxlgh)
                    {
                    char *s;

                    /* assert (stg[maxlgh]) is valid storage */
                    s = stg;
                    if (maxlgh && base)
                    do {
                    *s = hexify(number % base);
                    s++;
                    } while (--maxlgh && (number = number / base) );
                    *s = '\0';
                    revstring(stg);
                    return (s - stg);
                    } /* basedisplay */

                    /* =============== =============== =============== === */
                    /* convert signed number to string in various bases */
                    /* 2 <= base <= 16, controlled by hexify() */
                    /* Returns actual output string length */
                    size_t signbasedisplay (long number, unsigned int base,
                    char * stg, size_t maxlgh)
                    {
                    char *s;
                    size_t lgh;
                    unsigned long n;

                    s = stg; lgh = 0;
                    n = (unsigned long)number;
                    if (maxlgh && (number < 0L)) {
                    *s++ = '-';
                    maxlgh--;
                    n = -(unsigned long)number;
                    lgh = 1;
                    }
                    lgh = lgh + basedisplay(n, base, s, maxlgh);
                    return lgh;
                    } /* signbaseddispla y */


                    /* =============== ===== */
                    /* flush to end-of-line */
                    int flushln(FILE *f)
                    {
                    int ch;

                    while ('\n' != (ch = fgetc(f)) && (EOF != ch)) /* more */;
                    return ch;
                    } /* flushln */

                    /* ========== END of generically useful routines ============ */

                    /* =============== ========== */
                    /* Prompt and await <return> */
                    static void nexttest(char *prompt)
                    {
                    static char empty[] = "";

                    if (NULL == prompt) prompt = empty;
                    printf("\nHit return for next test: %s", prompt);
                    fflush(stdout);
                    flushln(stdin);
                    } /* nexttest */

                    /* =============== =============== */
                    /* Display a value and its length */
                    static void show(char *caption, int sz, char *stg)
                    {

                    if ((unsigned)sz != strlen(stg))
                    printf("Somethi ng is wrong with the sz value\n");
                    printf("%s: sz = %2d \"%s\"\n", caption, sz, stg);
                    } /* show */

                    /* =========== */
                    /* exercise it */
                    int main(void)
                    {
                    #define LGH 40
                    #define VALUE 1234567890

                    char stg[LGH];
                    unsigned int base;
                    int sz;

                    printf("\nExerc ising basedisplay routine\n");
                    printf("\nbase sz value\n");
                    for (base = 2; base <= 16; base++) {
                    sz = (int)basedispla y(VALUE, base, stg, LGH - 1);
                    printf("%2d %2d %s\n", base, sz, stg);
                    }

                    nexttest("ULONG _MAX");
                    for (base = 8; base <= 16; base++) {
                    sz = (int)basedispla y(ULONG_MAX, base, stg, LGH - 1);
                    printf("%2d %2d %s\n", base, sz, stg);
                    }

                    basedisplay(0, 10, stg, 3);
                    printf("\nzero %s\n", stg);

                    basedisplay(VAL UE, 10, stg, 3);
                    printf("3 lsdigits only, base 10 %s\n", stg);

                    printf("\nBad calls:\n");

                    sz = (int)basedispla y(VALUE, 10, stg, 0);
                    show("0 length field", sz, stg);

                    sz = (int)basedispla y(VALUE, 1, stg, 20);
                    show("base 1, lgh 20", sz, stg);

                    sz = (int)basedispla y(VALUE, 0, stg, 20);
                    show("base 0, lgh 20", sz, stg);

                    sz = (int)signbasedi splay(-1234, 10, stg, 0);
                    show("0 lgh fld, -ve", sz, stg);

                    sz = (int)signbasedi splay(-1234, 10, stg, 2);
                    show("truncate -1234", sz, stg);

                    nexttest("Syste m limits");

                    sz = (int)signbasedi splay(SCHAR_MIN , 10, stg, 20);
                    show("SCHAR_MIN ", sz, stg);

                    sz = (int)signbasedi splay(SCHAR_MAX , 10, stg, 20);
                    show("SCHAR_MAX ", sz, stg);

                    sz = (int)signbasedi splay(UCHAR_MAX , 10, stg, 20);
                    show("UCHAR_MAX ", sz, stg);

                    sz = (int)signbasedi splay(CHAR_MIN, 10, stg, 20);
                    show("CHAR_MIN ", sz, stg);

                    sz = (int)signbasedi splay(CHAR_MAX, 10, stg, 20);
                    show("CHAR_MAX ", sz, stg);

                    sz = (int)signbasedi splay(MB_LEN_MA X, 10, stg, 20);
                    show("MB_LEN_MA X ", sz, stg);

                    sz = (int)signbasedi splay(SHRT_MIN, 10, stg, 20);
                    show("SHRT_MIN ", sz, stg);

                    sz = (int)signbasedi splay(SHRT_MAX, 10, stg, 20);
                    show("SHRT_MAX ", sz, stg);

                    sz = (int)signbasedi splay(USHRT_MAX , 10, stg, 20);
                    show("USHRT_MAX ", sz, stg);

                    sz = (int)signbasedi splay(INT_MIN, 10, stg, 20);
                    show("INT_MIN ", sz, stg);

                    sz = (int)signbasedi splay(INT_MAX, 10, stg, 20);
                    show("INT_MAX ", sz, stg);

                    sz = (int)signbasedi splay(INT_MAX, 10, stg, 20);
                    show("INT_MAX ", sz, stg);

                    sz = (int) basedisplay(UIN T_MAX, 10, stg, 20);
                    show("UINT_MAX ", sz, stg);

                    sz = (int)signbasedi splay(LONG_MIN, 10, stg, 20);
                    show("LONG_MIN ", sz, stg);

                    sz = (int)signbasedi splay(LONG_MAX, 10, stg, 20);
                    show("LONG_MAX ", sz, stg);

                    sz = (int) basedisplay(ULO NG_MAX, 10, stg, 20);
                    show("ULONG_MAX ", sz, stg);

                    nexttest("DONE" );
                    return 0;
                    } /* main */

                    --
                    Chuck F (cbfalconer@yah oo.com) (cbfalconer@wor ldnet.att.net)
                    Available for consulting/temporary embedded and systems.
                    <http://cbfalconer.home .att.net> USE worldnet address!


                    Comment

                    Working...