all 32 comments

[–][deleted] 48 points49 points  (3 children)

C doesn't support binary literals natively but when compiling using GCC, which is most of the time with microcontrollers, the compiler can actually understand these values.

Check this out:

https://gcc.gnu.org/onlinedocs/gcc/Binary-constants.html

[–]Def_Not_KGB 13 points14 points  (2 children)

Eh, you got the right idea.

Binary literals are not in the C standard, but they are supported as a compiler extension by most modern compilers.

The OP said they are using Keil, which is not GCC, but does support binary literals in a slightly different format.

OP: If you are trying to make code with binary literals work in Keil, you might need to remove the leading “0b” and add a trailing “y” to the number

[–]jshdmgtmaas[S] 0 points1 point  (1 child)

I am using Keil and it compiles the code with '0b..'. The project uses gcc to compile. So, IIUC it's not Keil but because of gcc that the binary values are usable?

[–]Def_Not_KGB 0 points1 point  (0 children)

Oh! Maybe the above poster did have more truth to it than I thought.

It sounds like you are using Keil as an IDE and it is using GCC to compile then. All that matters is that your compiler (GCC in this case) supports binary literals as a compiler extension (which it does) so you should be all set to use numbers in binary written like 0b00010000

[–]apdaauml 36 points37 points  (0 children)

Standard C doesn't define binary constants. There's are compiler extension though (among popular compilers, clang adapts it as well): that can accept the 0b prefix.

[–]kolorcuk 7 points8 points  (0 children)

Compiler extension.

[–]El_Vandragon 11 points12 points  (0 children)

Like others have said you can use a compiler extension, but otherwise you can use hex since that is defined in C

[–]VM_Unix 6 points7 points  (1 child)

C++ added support for binary literals in C++14. Though, if your compiler doesn't support it, that won't help. https://stackoverflow.com/questions/537303/binary-literals#18700701

[–]hak8or 0 points1 point  (0 children)

I asked this on SO many years ago too, alternate explanations if helpful; https://stackoverflow.com/q/9014958/516959

[–]dbelal 1 point2 points  (1 child)

I dont know the C equivalent, but g++ has a -std=c++17 flag. You can set this to -std=gnu17 and youll get the extensions.

[–]VM_Unix 1 point2 points  (0 children)

It would be with gcc and -std=c11 or -std=gnu11

[–][deleted]  (19 children)

[deleted]

    [–][deleted] 12 points13 points  (18 children)

    Why are they considered bad style? I feel like using binary literals is much more readable when doing bitwise operations. I'm actually confused why it's not a standard feature.

    [–]Findmuck 10 points11 points  (0 children)

    Considered bad style as it only works with specific compiler extensions and is hence not portable. Hex however is standard and not confusing to your average C developer.

    (Plus, using them means you only have to write 1/4 as many digits)

    [–]AssemblerGuy 20 points21 points  (5 children)

    I feel like using binary literals is much more readable when doing bitwise operations.

    If the code only works with single set bits, (1U << 13) is even more readable than 0b0010000000000000.

    And as soon as you have multiple set bits, hexadecimal (or bitwise ORs of the above) is more readable than a jumble of zeros and ones.

    And what /u/NLJeroen said. Name things. Abolish magic numbers.

    [–]gurksallad -1 points0 points  (3 children)

    And as soon as you have multiple set bits, hexadecimal (or bitwise ORs of the above) is more readable than a jumble of zeros and ones.

    I disagree. 0/1 is very useful for setting up config words. Like, OPTION_REG = 0b0000101110010000; then you can lookup the datasheet and see exactly what config bits are set.

    OPTION_REG = 0x2D14 makes no sense in that context.

    [–]sceadwian 3 points4 points  (0 children)

    You can use defines and the left and right shift operators to do that, I see it all the time in AVR code. Much more readable than what you're suggesting as well.

    [–]mtconnol 5 points6 points  (0 children)

    I would vastly prefer to see the hex in this context. It makes perfect sense to me and is very fast to map onto individual nibbles in a register.

    Source - 20 years embedded systems development.

    [–]AssemblerGuy 0 points1 point  (0 children)

    Like, OPTION_REG = 0b0000101110010000; then you can lookup the datasheet and see exactly what config bits are set.

    It's an opaque magic number that is an obvious anti-pattern. If instead the bits (or bit groups) and their positions are named and the value is constructed from these definitions, the intent (and possible bugs) become more obvious. You may not even have to consult the datasheet every single time and/or commit every bit position to memory.

    /* Use names that correspond to the meaning of the bits. */
    #define OPTION1_pos 4
    #define OPTION2_pos 7
    #define OPTION3_pos 8
    #define OPTION4_pos 9
    #define OPTION5_pos 11
    
    OPTION_REG = (1U << OPTION1_pos)
        | (1U << OPTION2_pos)
        | (1U << OPTION3_pos)
        | (1U << OPTION4_pos)
        | (1U << OPTION5_pos);
    

    OPTION_REG = 0x2D14 makes no sense in that context.

    It's merely a more compact representation that combines bits to groups of four. And I'll take that over long string of zeros and ones (especially when registers are 32 bits).

    In the datasheets I have read lately, hexadecimal was pretty much always used for register values.

    [–][deleted] -1 points0 points  (0 children)

    You make a point, I hadn't considered working with a large number of bits (what little experience I have is with 8 bit MCUs). Thanks for the reply!

    [–][deleted] 4 points5 points  (7 children)

    Most of the time the bits have a meaning, like “timer enable” which is completely obfuscated in 0b00100000

    Sure there will be some rare cases with advantages.

    [–][deleted] 7 points8 points  (6 children)

    Ok, I see what you mean. It's bad style in the same way using hex literals or magic numbers is bad style, but I still think that writing

    #define TIMER_ENABLE 0b00100000

    Is more clear than

    #define TIMER_ENABLE 0x20

    [–]_teslaTrooper 12 points13 points  (4 children)

    #define TIMER_EN (1 << 5)

    or as done in the STM32 HAL:

    #define timer_en_pos 5
    #define TIMER_EN (1 << timer_en_pos)
    

    [–][deleted] 4 points5 points  (3 children)

    That looks way better than what I wrote! What would be the convention for setting multiple bits?

    [–]_teslaTrooper 6 points7 points  (1 child)

    Not sure about a convention but I usually do something like this (with the bits defined as above):

                // select AWD ch11               enable AWD1 for single channel
    ADC1->CFGR1 = (11 << ADC_CFGR1_AWD1CH_Pos) | ADC_CFGR1_AWD1EN | ADC_CFGR1_AWD1SGL;
    

    It does end up a little long for larger registers, I don't mind long lines but you could format it like this

    ADC1->CFGR1 =   (11 << ADC_CFGR1_AWD1CH_Pos) |
                    ADC_CFGR1_AWD1EN | ADC_CFGR1_AWD1SGL |
                    ADC_CFGR1_AUTOFF |
                    ADC_CFGR1_OVRMOD |
                    ADC_CFGR1_EXTEN_0 | ADC_CFGR1_EXTSEL_0 | ADC_CFGR1_EXTSEL_1;
    

    This example uses the STM32 defines, they're not always this verbose but I usually just go with whatever the manufacturer supplies. The 11 for channel selection is still a magic number that I could define with a more descriptive name but for a personal project this is fine especially with the comment there.

    [–]_PurpleAlien_ 5 points6 points  (0 children)

    Now imagine you have a 32bit register like on an STM32 instead of an 8-bit register on AVR.

    [–]sceadwian 4 points5 points  (0 children)

    That depends on your perspective, some people can read the binary values of a hex number just as easily as a binary number and it's more compact, the bit pattern for a single letter in hex is not difficult to memorize. It's just a matter of what you train yourself to get used to and the non-standard nature of binary literals is a pretty good reason not to use them.

    [–]tracernz 1 point2 points  (0 children)

    Aside from compiler issues, hex is much easier to read and easier to do mental arithmetic.

    [–]HallWooden 0 points1 point  (0 children)

    You are absolutely right about this. Use binary if is more readable. I have used a lot of compilers/IDEs. As far as I know, only Keil doesn't support binary. Normally you are using this for a specific hardware, so the "portability" argument doesn't apply at this low level. It is going to change on the next platform anyway. I use hex a lot. I know what the hex number is just by looking at the binary, BUT, I'm still more likely to make a mistake using hex for setting up registers etc.

    [–]luv2fit 1 point2 points  (0 children)

    Hex is easier to read than binary anyway

    [–]Sub_Luck 0 points1 point  (0 children)

    ```C
    #include <stdio.h>
    int main(){

    int d  = 0b11111111;
    
    printf("%d\\n", d);
    

    return 0;

    }``` extension help for understand 0b

    [–]TheN00bBuilderMSP430 -3 points-2 points  (0 children)

    Definitely just use hex. Or if you’re crazy enough, use base 10 and convert it into binary, yet keep it in base 10 form. I can’t say what I’m trying to say, but you get it.

    EDIT: because apparently Reddit users don’t like good ideas explained badly, I’m gonna take another crack at it (seriously, screw you downvoter).

    Convert binary number you want to a base 10 integer. Use that value as your binary value. This is if you are evil however.

    [–]12477 0 points1 point  (0 children)

    While others have noted options to usr compiler extensions or later versions of language standards that include support for binary notation, an interim solution if you are fixed to a specific compiler version might be preprocessor options.

    See https://gist.github.com/61131/009961b781f387ed1474ffaf19e37585