Douglas Marsh
Douglas Marsh

Reputation: 31

gcc bitwise odd behavior

I'm getting back to C after a long absence and I'm trying to learn the bitwise operators. I wrote this little program to demonstrate my confusion. The first printf works (after the header), but not the second. Is this some kind of order of operations thing or what?

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

const char *byte_to_binary(int x)
{
    static char b[9];
    b[0] = '\0';

    int z;
    for (z = 128; z > 0; z >>= 1)
        {
        strcat(b, ((x & z) == z) ? "1" : "0");
        }

    return b;
}

int main(int argc, char *argv[])
{
    unsigned int ch = atoi(argv[1]);
    unsigned int a = atoi(argv[2]);
    int chA;
    int chB;
    int chC;
    int chD;
    int chE;
    int chF;
    chA = ch & a;
    chB = ch | a;
    chC = ch ^ a;
    chD = ~ch;
    chE = ch << 2;
    chF = ch >> 2;
    char chAS[16];
    char chBS[16];
    char chCS[16];
    char chDS[16];
    char chES[16];
    char chFS[16];
    strcpy(chAS, byte_to_binary(chA));
    strcpy(chBS, byte_to_binary(chB));
    strcpy(chCS, byte_to_binary(chC));
    strcpy(chDS, byte_to_binary(chD));
    strcpy(chES, byte_to_binary(chE));
    strcpy(chFS, byte_to_binary(chF));

    printf("[c][%%d ][%%o ][%%x][   %%s  ][   &    ][   |    ][   ^    ][   ~    ][  <<    ][   >>   ]\n");
    printf("[%c][%03d][%03o][%02x][%s][%s][%s][%s][%s][%s][%s]\n", isprint(ch) ? ch : ' ', ch, ch, ch, byte_to_binary(ch), chAS, chBS, chCS, chDS, chES, chFS);
    printf("[%c][%03d][%03o][%02x][%s][%s][%s][%s][%s][%s][%s]\n", isprint(ch) ? ch : ' ', ch, ch, ch, byte_to_binary(ch), byte_to_binary(ch & a), byte_to_binary(ch | a), byte_to_binary(ch ^ a), byte_to_binary(~ch), byte_to_binary(ch << 2), byte_to_binary(ch >> 2));

    return (0);
}

Upvotes: 0

Views: 63

Answers (3)

KamilCuk
KamilCuk

Reputation: 140900

const char *byte_to_binary(int x)
{
    static char b[9];
    ...
    return b;
}

This function is not reentrant and returns a pointer to local value. So using it like : byte_to_binary(ch), byte_to_binary(ch & a) will yield the same result twice, as the pointer value is the same(!).

But you can pass allocated space to your function:

const char *byte_to_binary(int x, char b[9]) { 
   ...
   return b; 
}

And call using constant literal:

byte_to_binary(ch, (char[9]){0}), byte_to_binary(ch & a, (char[9]){0}),

This will allocate needed 9 chars on each function call. You can make that a macro:

const char *byte_to_binary_in(int x, char b[9]) { 
   ...
   return b; 
}
#define byte_to_binary(x)  byte_to_binary_in(x, (char[9]){0})

And have stay with the same interface, while your function stays reentrant.

Keep in mind however, that compound literals stop existing when exiting from a block, ie. after }.

P.S. Have fun and see my small function printbinary and macro PRINTBINARY_t(...), header and src. However there are maaany solution over the net for printing binary numbers.

Upvotes: 0

Arkku
Arkku

Reputation: 42109

You are returning a pointer to the same static buffer from every call to byte_to_binary, so by the time the printf reads them they have (or rather, it has) only the last result.

Upvotes: 1

dbush
dbush

Reputation: 223699

Your byte_to_binary function returns a pointer to a static array. You then call printf, passing the return value of this function multiple times, and each of those calls returns the same pointer, so whichever invocation of the function happens to come last will be the one the results are printed for in all cases.

You need to either split up your printf calls so that byte_to_binary is only called once each time, or copy off the result into temporaries and print those. You're doing the latter in the second printf call, so just use that and remove the third.

Upvotes: 2

Related Questions