views:

189

answers:

3

I would like to be able to enter a character from the keyboard and display the binary code for said key in the format 00000001 for example.

Furthermore i would also like to read the bits in a way that allows me to output if they are true or false.

e.g.

01010101 = false,true,false,true,false,true,false,true

I would post an idea of how i have tried to do it myself but I have absolutely no idea, i'm still experimenting with C and this is my first taste of programming at such a low level scale.

Thankyou

+4  A: 

This is probably not the safest way - no sanity/size/type checks - but it should still work.

unsigned char myBools[8];
char myChar;  

// get your character - this is not safe and you should
// use a better method to obtain input...
// cin >> myChar; <- C++
scanf("%c", &myChar);

// binary AND against each bit in the char and then
// cast the result. anything > 0 should resolve to 'true'
// and == 0 to 'false', but you could add a '> 1' check to be sure.
for(int i = 0; i < 8; ++i)
{
   myBools[i] = ( (myChar & (1 << i) > 0) ? 1 : 0 );
}

This will give you an array of unsigned chars - either 0 or 1 (true or false) - for the character.

acron
Should probably put parentheses around (1 << i)?
Sam Post
Edited - but can you check it because my C isn't as strong as my C++.
acron
If you want scanf to read in a number, try %d
Sam Post
I think OP wants any character.
acron
The scanf should be `scanf("%c", `
interjay
Edited - cheers.
acron
I thought there wasn't a type called "bool" in c?
Jamie Keeling
@Jamie Keeling - Depends GNUC does have it using #ifndef __GNUC__ #include<bool.h> #endif
Aiden Bell
Ah well, you get the idea :p I'm a new-school C++ coder.
acron
@acron: Thank you for trying, personally im used to C# so I'm about as knowledgeable as you Haha.@Aiden Bell: "bool.h" doesn't exist.
Jamie Keeling
Edited to use an unsigned char instead of bool. 0 being false, 1 being true.
acron
@Jamie, then your not on a platform that supports it outside the standard. You can typedef your own ;)
Aiden Bell
+3  A: 

For bit tweaking, it is often safer to use unsigned types, because shifts of signed negative values have an implementation-dependent effect. The plain char can be either signed or unsigned (traditionally, it is unsigned on MacIntosh platforms, but signed on PC). Hence, first cast you character into the unsigned char type.

Then, your friends are the bitwise boolean operators (&, |, ^ and ~) and the shift operators (<< and >>). For instance, if your character is in variable x, then to get the 5th bit you simply use: ((x >> 5) & 1). The shift operators moves the value towards the right, dropping the five lower bits and moving the bit your are interested in the "lowest position" (aka "rightmost"). The bitwise AND with 1 simply sets all other bits to 0, so the resulting value is either 0 or 1, which is your bit. Note here that I number bits from left significant (rightmost) to most significant (leftmost) and I begin with zero, not one.

If you assume that your characters are 8-bits, you could write your code as:

unsigned char x = (unsigned char)your_character;
int i;

for (i = 7; i >= 0; i --) {
    if (i != 7)
        printf(",");
    printf("%s", ((x >> i) & 1) ? "true" : "false");
}

You may note that since I number bits from right to left, but you want output from left to right, the loop index must be decreasing.

Note that according to the C standard, unsigned char has at least eight bits but may have more (nowadays, only a handful of embedded DSP have characters which are not 8-bit). To be extra safe, add this near the beginning of your code (as a top-level declaration):

#include <limits.h>
#if CHAR_BIT != 8
#error I need 8-bit bytes!
#endif

This will prevent successful compilation if the target system happens to be one of those special embedded DSP. As a note on the note, the term "byte" in the C standard means "the elementary memory unit which correspond to an unsigned char", so that, in C-speak, a byte may have more than eight bits (a byte is not always an octet). This is a traditional source of confusion.

Thomas Pornin
+1, some good tippage there.
Aiden Bell
+3  A: 

This code is C89:

/* we need this to use exit */
#include <stdlib.h>
/* we need this to use CHAR_BIT */
#include <limits.h>
/* we need this to use fgetc and printf */
#include <stdio.h>

int main() {
    /* Declare everything we need */
    int input, index;
    unsigned int mask;
    char inputchar;

    /* an array to store integers telling us the values of the individual bits.
       There are (almost) always 8 bits in a char, but it doesn't hurt to get into
       good habits early, and in C, the sizes of the basic types are different
       on different platforms. CHAR_BIT tells us the number of bits in a byte. 
     */
    int bits[CHAR_BIT];

    /* the simplest way to read a single character is fgetc, but note that
       the user will probably have to press "return", since input is generally 
       buffered */
    input = fgetc(stdin);
    printf("%d\n", input);

    /* Check for errors. In C, we must always check for errors */
    if (input == EOF) {
        printf("No character read\n");
        exit(1);
    }

    /* convert the value read from type int to type char. Not strictly needed,
       we can examine the bits of an int or a char, but here's how it's done. 
     */
    inputchar = input;

    /* the most common way to examine individual bits in a value is to use a 
       "mask" - in this case we have just 1 bit set, the most significant bit
       of a char. */
    mask = 1 << (CHAR_BIT - 1);

    /* this is a loop, index takes each value from 0 to CHAR_BIT-1 in turn,
       and we will read the bits from most significant to least significant. */
    for (index = 0; index < CHAR_BIT; ++index) {
        /* the bitwise-and operator & is how we use the mask.
           "inputchar & mask" will be 0 if the bit corresponding to the mask
           is 0, and non-zero if the bit is 1. ?: is the ternary conditional
           operator, and in C when you use an integer value in a boolean context,
           non-zero values are true. So we're converting any non-zero value to 1. 
         */
        bits[index] = (inputchar & mask) ? 1 : 0;

        /* output what we've done */
        printf("index %d, value %u\n", index, inputchar & mask);

        /* we need a new mask for the next bit */
        mask = mask >> 1;
    }

    /* output each bit as 0 or 1 */
    for (index = 0; index < CHAR_BIT; ++index) {
        printf("%d", bits[index]);
    }
    printf("\n");

    /* output each bit as "true" or "false" */
    for (index = 0; index < CHAR_BIT; ++index) {
        printf(bits[index] ? "true" : "false");
        /* fiddly part - we want a comma between each bit, but not at the end */
        if (index != CHAR_BIT - 1) printf(",");
    }
    printf("\n");
    return 0;
}

You don't necessarily need three loops - you could combine them together if you wanted, and if you're only doing one of the two kinds of output, then you wouldn't need the array, you could just use each bit value as you mask it off. But I think this keeps things separate and hopefully easier to understand.

Steve Jessop
+1 for a thorough example, which caused me to delete my own. Anyone else (unless stubborn or stupid) should do the same ;)
Aiden Bell
Very thorough, unfortunately when pasted into a blank source file I'm presented with 45 errors, mostly syntax errors and undeclared identifiers.
Jamie Keeling
What compiler are you using?
Steve Jessop
Probably MSVC. I've provided C89 code.
Steve Jessop
Excellent, works wonderfully. Thank you for such a wonderful explanation of your solution as well.
Jamie Keeling