Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

That’s what functions and automatic compiler inlining are for. See verserv’s answer https://news.ycombinator.com/item?id=28776751


No, using functions for such things is worse.

It does not matter if the compiler inlines them, encapsulating the bit field operations obfuscates the code instead of making it more easily understandable.

It is not possible to make the name of the function to provide more information than the triplet register name + bit field name (the name of the shift constant) + the name of the configuration option (the name of the mask constant).

Encapsulating the bit operations into a function just makes you write exactly the same thing twice and when you are reading the code you must waste extra time to check each function definition to see whether it does the right thing.

The C code would look just like a table with the names, where the operators just provide some delimiters in the table that occupy little space.

Replacing the operators with words makes such code less readable and concatenating the named constants into function names or using them as function arguments brings no improvement.

The only possible improvement over explicit bit operations is to define the registers as structures with bit-field members and use member assignment instead of bit string operations.

Unfortunately the number of register definitions for any CPU is huge, so most programmers use headers provided by the hardware vendor, as it would be too much work to rewrite them.

For almost all processors with which I have worked, the hardware vendor has preferred to provide names for mask constants and shift constants, instead of defining the registers as structures, even if the latter would have allowed more easy to read code.


> you must waste extra time to check each function definition to see whether it does the right thing

I think I see what you're arguing. That this:

    reg1 &= ~(width_mask_1 << shift);
    reg2 &= ~(width_mask_2 << shift);
    reg3 &= ~(width_mask_3 << shift);
    // etc...
is clearer than something like this:

    reg1 = ClearBitField(reg1, 1, shift);
    reg2 = ClearBitField(reg2, 2, shift);
    reg3 = ClearBitField(reg3, 3, shift);
    // etc...
If that's what you're arguing, I simply don't agree. `ClearBitField` is descriptive and readable. It avoids creating all those width_mask_n constants, since you specify the width as input to the fn. You don't have to go digging into `ClearBitField` because you wrote a unit test to confirm that it does what it says on the label and handles the edge cases.

On top of that, the code inside `ClearBitField` can be as verbose or as compact as you desire, because it's contained and separated from the rest of the code.


I find the first code example easier to read and process.

However, that's because I've written a fair bit of C code, and so when my brain goes into "C mode", the symbols &, =, ~, <<, etc. all have clear and unambiguous meanings - whereas ClearBitField does not. Additionally, the pattern ~(foo << bar) is a common C idiom, so beyond the individual symbols, my brain recognizes the whole pattern so it's "semantically compressed" (easier to think about) for me. This would not be the case for a beginner.

Which style is better depends on an individual's preferences and experiences - there's no "right" answer.

This is a stellar example of one of the many reasons why code-as-text is a huge mistake - because structure and representation are conflated and coupled together. A sanely written programming language represents code as code objects, and you can configure those code objects to be displayed however you like, whether that's baz &= ~(foo << bar) or ClearBitField(baz, 1, bar).


Obviously this is a matter of personal preferences and experience.

Real register names are usually very long, to indicate their purpose, so you would not want to repeat them on each line.

This can be avoided by redefining ClearBitField.

Even so, writing an extra "ClearBitField" on each line does not provide any information. It just clutters the space.

Anyone working with such code is very aware that &=~ means clear bits and |= means set bits.

When reading the table of names, the repeated function name is just a distraction that is harder to overlook than the operators.

The way to improve over that is not adding anything on the lines, but using simpler symbols by defining the registers as structures, i.e.:

register_1 . bit_field_1 = constant_name_1;

register_2 . bit_field_2 = constant_name_2;

register_3 . bit_field_3 = constant_name_3;

Unfortunately, like I have said, the hardware vendors seldom provide header files with structure definitions for the registers and rewriting the headers is a huge work.

However, if you are able to rewrite just the register definitions that you use, that would be better spent time than attempting to write functions or macros for these tasks.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: