Why doesn't C have binary literals?

44,814

Solution 1

According to Rationale for International Standard - Programming Languages C §6.4.4.1 Integer constants

A proposal to add binary constants was rejected due to lack of precedent and insufficient utility.

It's not in standard C, but GCC supports it as an extension, prefixed by 0b or 0B:

 i = 0b101010;

See here for detail.

Solution 2

This is what pushed hexadecimal to be... hexadecimal. The "... primary use of hexadecimal notation is a human-friendly representation of binary-coded values in computing and digital electronics ...". It would be as follows:

val1 |= 0xF;
val2 &= 0x40;
val3 |= ~0x10;

Hexadecimal:

  1. One hex digit can represent a nibble (4 bits or half an octal).
  2. Two hex digits can represent a byte (8 bits).
  3. Hex is much more compact when scaling to larger masks.

With some practice, converting between hexadecimal and binary will become much more natural. Try writing out your conversions by hand and not using an online bin/hex notation converter -- then in a couple days it will become natural (and quicker as a result).

Aside: Even though binary literals are not a C standard, if you compile with GCC it is possible to use binary literals, they should be prefixed with '0b' or '0B'. See the official documentation here for further information. Example:

int b1 = 0b1001; // => 9
int b2 = 0B1001; // => 9

Solution 3

All of your examples can be written even more clearly:

val1 &= (1 << 4) - 1; //clear high nibble
val2 |= (1 << 6); //set bit 6
val3 &=~(1 << 3); //clear bit 3

(I have taken the liberty of fixing the comments to count from zero, like Nature intended.)

Your compiler will fold these constants, so there is no performance penalty to writing them this way. And these are easier to read than the 0b... versions.

Solution 4

I think readability is a primary concern. Although low-level, it's human beings who read and maintain your code, not machine.

Is it easy for you to figure out that you mistakenly typed 0b1000000000000000000000000000000(0x40000000), where you really mean 0b10000000000000000000000000000000(0x80000000) ?

Solution 5

"For example, if reg is a register that controls I/O pins on a microcontroller"

I can't help thinking this is a bad example. Bits in control registers have specific functions (as will any devices connected to individual IO bits).

It would be far more sensible to provide symbolic constants for bit patterns in a header file, rather than working out the binary within the code. Converting binary to hexadecimal or octal is trivial, remembering what happens when you write 01000110 to an IO register is not, particularly if you don't have the datasheet or circuit diagram handy.

You will then not only save those 10 seconds trying to work out the binary code, but maybe the somewhat longer time trying to work out what it does!

Share:
44,814

Related videos on Youtube

Drew
Author by

Drew

Updated on July 09, 2022

Comments

  • Drew
    Drew almost 2 years

    I am frequently wishing I could do something like this in c:

    val1 &= 0b00001111; //clear high nibble
    val2 |= 0b01000000; //set bit 7
    val3 &= ~0b00010000; //clear bit 5
    

    Having this syntax seems like an incredibly useful addition to C with no downsides that I can think of, and it seems like a natural thing for a low level language where bit-twiddling is fairly common.

    Edit: I'm seeing some other great alternatives but they all fall apart when there is a more complex mask. For example, if reg is a register that controls I/O pins on a microcontroller, and I want to set pins 2, 3, and 7 high at the same time I could write reg = 0x46; but I had to spend 10 seconds thinking about it (and I'll likely have to spend 10 seconds again every time I read those code after a not looking at it for a day or two) or I could write reg = (1 << 1) | (1 << 2) | (1 << 6); but personally I think that is way less clear than just writing `reg = 0b01000110;' I can agree that it doesn't scale well beyond 8 bit or maybe 16 bit architectures though. Not that I've ever needed to make a 32 bit mask.

    • vroomfondel
      vroomfondel almost 11 years
      it has hex, which in my opinion is even better, if you spend 10 minutes getting a feel for the relationship
    • Nemo
      Nemo almost 11 years
      Should that last comment read "clear bit 4"? (Or better yet, "clear bit 3", since programmers should count from zero by default?)
    • The Mask
      The Mask almost 11 years
      IMHO, because there's hex. Much more easy to programmer use than binary numbers. It's very error-prone. Not matter how experient you is.
    • jxh
      jxh almost 11 years
      Did you already see this?
    • chux - Reinstate Monica
      chux - Reinstate Monica almost 11 years
      C has "binary" literals, but only 2 of them: 0, 1. ;-)
    • Nemo
      Nemo almost 11 years
      For what it's worth, C++14 will have these.
    • Ed S.
      Ed S. about 10 years
      We have hex literals. All of your examples are about bit masking. I have no problem figuring out which bit is being turned on/off/whatever when I read 0x80.
    • 12431234123412341234123
      12431234123412341234123 over 7 years
      Your comments are wrong: instruction 1: set all bits in the low nibble, instruction 2: clear every bit exept bit 6 (not bit 7, bit start with 0), instruction 3: set every bit except bit 4 (again not bit 5)
    • pmg
      pmg almost 7 years
      #define B00000000 0 #define B00000001 1 #define B00000010 2 #define B00000011 3 ... #define B10100100 0xA4 ... possibly with a cast to unsigned char.
    • AnT stands with Russia
      AnT stands with Russia over 5 years
      @chux: 0 actually an octal literal.
    • chqrlie
      chqrlie over 5 years
      @AnT: more precisely, 0 is an octal-constant
    • M.J. Rayburn
      M.J. Rayburn over 5 years
      Possible duplicate of Binary literals?
  • Drew
    Drew almost 11 years
    Yes that is what I always end up doing instead, but I always have to do a bunch of calculations in my to remember what binary is what in hax. Especially if I want to eg. clear the lowest 6 bits. And I agree that binary literals would get long for 32 bit platforms, but in that case you can just not use them.
  • Drew
    Drew almost 11 years
    Thats awesome but I'm not using GCC :( do you know what its not in the standard?
  • markgz
    markgz almost 11 years
    Thinking in hex becomes second nature after a little practice. Hex also has the advantage that it is easier to read than binary.
  • Jacob Pollack
    Jacob Pollack almost 11 years
    @Drew, I understand your point of view as it may be visually much easier to think about for smaller masks. Once you have practiced enough it will come fairly natural (as everything comes in life). I recommend doing all calculations out by hand and double check yourself on a calculator when creating masks so that you can get better and converting between the two notations.
  • Yu Hao
    Yu Hao almost 11 years
    @Drew See the update. In another word, the committee thinks its usage can be covered by hex constants, I think.
  • Drew
    Drew almost 11 years
    This seems like the best reason so far. Still, though, you don't have to use binary in those cases. And how often do you make a 32 bit mask anyway?
  • lurker
    lurker almost 11 years
    How much mental math does it really take to imagine the binary value represented by a hex number? Of all the operations/calculations that a good programmer needs to do in their head, I think this one is one of the simplest.
  • Eric Z
    Eric Z almost 11 years
    Since they have a better alternative(hexdecimal) in most cases, I guess the committee just close the door to such mistakes by not providing it.
  • Nemo
    Nemo almost 11 years
    @Jerry Well, that will teach me not to stop thinking after the first error. Thanks
  • The Mask
    The Mask almost 11 years
    +1 I don't knew really that's the primary use of hex notation. Good know!
  • David Given
    David Given about 9 years
    This is going to do a runtime string decode, three times, every time this code is run. That's not going to do well for performance.
  • Abraham Sanchez
    Abraham Sanchez over 8 years
    If we take into account endianness, is (1 << 4) - 1 really the same as 0xF ? ... maybe not.
  • Nemo
    Nemo over 8 years
    @AbrahamSanchez: Yes, it is exactly the same on all platforms. Arithmetic operations like left shift are defined independently of endianness. (In fact, endianness is not even detectable unless you cast a pointer or use a union.)
  • Hans Dampf
    Hans Dampf over 8 years
    please change "4 bytes" to "4 bits" in bullet point 1. One nibble is 4 bits, not bytes.
  • yyny
    yyny about 8 years
    @Nemo or a array, or a struct, or any other variable. As long as you use some hack like the memcpy one everything is possible.
  • Nemo
    Nemo about 8 years
    @YoYoYonnY: All of those require that you "cast a pointer or use a union", as I said.
  • yyny
    yyny about 8 years
    @Nemo I think 'dereference' is a better term, but you're right, I'm sorry. I was just trying to point out that you can use any memory type to check endianness using a hack like memcpy or memset or something similair, as long as its size is over 1 byte)
  • Lesto
    Lesto about 8 years
    but this make more hard to understand some other cases, for example if that is a register where bit may have different meaning, having to take out the calculator to see what bit are enabled/disabled is just a complication. This is a common case when dealing with i2c/spi sensors.
  • Eric Z
    Eric Z almost 8 years
    @lesto, That's where hex form are mostly used. It's easy to tell the binary code from hex.
  • 12431234123412341234123
    12431234123412341234123 over 7 years
    just because you can write unreadable code with a feature, it is not a reason to not allow it. you can always write unreadable code with every language if you want.
  • 463035818_is_not_a_number
    463035818_is_not_a_number over 5 years
    you say "It's easy to tell the binary code from hex" but your question lives upon the premise that its hard to tell the hex from the binary. I dont really buy that. Even if I would, just because it can be misused (you wouldnt really use a binary literal when it has ~20 digits) doesnt mean that it can help sometimes
  • Lundin
    Lundin about 5 years
    " but then who actually ports something like this anyhow?" People who change compiler for the same hardware. Roughly 100% of all embedded systems programmers have to do that at some point in their career.
  • sleblanc
    sleblanc over 3 years
    @DavidGiven, it is trivial for a compiler to optimize the values to compile-time constants. No runtime decoding is performed.
  • Kurt E. Clothier
    Kurt E. Clothier about 2 years
    Sometimes I think the people write standards don't actually code anything in the language they are standardizing. That, or they are all part of the same niche tech space and can't fathom that anyone uses the language for anything other than what they use it for.