Ah,
many interesting point for discussion!
One premise: I refer to C99, as it introduces a number of new functionalities that (IMO) lead to cleaner and more understandable code.
To use C99 with gcc, just add the std=c99 to the compilation flags, or std=gnu99 if you want to use gcc specific extensions (binary constants, inline assembler etc.).
ETA: I checked, the default is actually gnu11.
Well i am trying to make life simple while trying to not break things. If I just stick register manipulations in my code i will just be commenting the crap out of everything at which point I'll still have to write it all out in advance with comments ready to copy and paste.
Yes, I see you are trying to build some kind of library, and replace bit-setting with meaningful names.
That's quite an effort, probably a bit tedious, but not a bad idea if you are so inclined: after all that's what most vendor-provided libraries try to achieve (with varying degree of success...).
Clearly GNU added it because it is aimed at embedded systems where binary works well as we deal with some 8 or 16 bit numbers on a bit by bit basis.
gcc is very general, definitely not born for or specifically aimed at embedded code.
During C99 standardization, the binary constant were proposed and rejected (
Ch 6.4.1 in the C99 rationale):
A proposal to add binary constants was rejected due to lack of precedent and insufficient utility.
Personally, I prefer using hex, as I tend to very quickly lose track of the digit positions in long numbers.
Here C++14 got it quite right: you have binary constants with expected
0b prefix, and single quotes in numbers are ignored, so one can group the digits as they see fit.
[...]so what does object like form mean?
Object-like and function-like are the actual terms used in the standard (
6.10.3, cl. 9&10), their meaning is pretty simple.
An object-like macro is defined and appears in the code as an identifier (like the ones you defined!):it takes no parameters (what the replacement text does is completely free).
A function-like macro is defined with a list of parameters, as a (guess what!) function, and as such is invoked in the code.
In C you don't expect in general that simply naming an identifier will carry on some action, that's the reason for suggesting the use of a function-like macro. In your case, it's enough to add (), as there are no parameters:
#define TCA0_CLKSEL_DIV64() TCA0.CTRLA = ((TCA0.CTRLA & 0b11110001) | 0b00001010) // <= note the () !
It makes it clear that something is changing, as a function can be expected to have side effects.
I learnt C after Pascal, and the most common bug in my beginners programs was to call functions forgetting the ()...then wondering why nothing happened
:
As i said, I still find this kind of definition problematic: the do {...} while(0) bracketing helps, though it's normally used when one wants more than one statement inside a macro.
#define TCA0_CLKSEL_DIV64() do { TCA0.CTRLA = ((TCA0.CTRLA & 0b11110001) | 0b00001010); } while (0)
In this way, we have now something safer, that can be used more or less as any "void function(void)".
Are you suggesting that instead of macro's/defines I use functions?
Exactly! But not any old function
C99 introduced the concept of inline functions, one of the most useful characteristics is that they can replace function-like macros, with the advantage of retaining the same speed, having a clear and known syntax, and perform type checking of the parameters.
An inline function, declared also static, is visible only in the translation unit where it's defined and declared, so its natural place is in an include file, exactly as your macro!
static inline void TCA0_CLKSEL_DIV64(void) { TCA0.CTRLA = ((TCA0.CTRLA & 0b11110001) | 0b00001010); }
Now all ambiguities and syntax corner cases are solved.
As for the speed, the compiler will
inline the function, i.e. the the assignment will be baked in the code, with no call/return overhead.
Gcc and most other modern compilers do that, for gcc optimization flag must not be -O0 (no optimization), any other will do.There are some things to be careful with when using inline, but if you just use static inline, it's easy.
while (1)
{
PD2_HI;
PD2_LOW;
PD2_HI;
PD2_LOW;
}
Yep, looks like Pascal!