I've discovered that the "[b]_BV()[/b]" macro (located in "[b]arduino-1.0.x/hardware/tools/avr/lib/avr/include/avr/sfr_defs.h[/b]") doesn't work if the bit value is 15 or higher.
The macro is simple:
#define _BV(bit) (1 << (bit))
My theory as to why it fails is that the value shifted (1) is by default an int (i.e. a signed 16 bit number which cannot be larger than +32767). To test my theory, I changed the macro to this...
#define _BV(bit) ((uint64_t) 1 << (bit))
...and ta-daa it works.
My questions are:
Will this still operate as before (i.e. expanded by the pre-processor and only be a value, not code)?
Should I use uint64_t, uint32_t or size_t?
Should I replace the macro with a bunch of pre-defines (like this):
(1) I usually don't need anything 64 bit, but I thought why not give it all the functionality possible?
(2) You're right. I didn't at all like that idea, I simply tossed it in there as a possibility.
(3) Wow, I didn't know about the bit macro. It's the same as _BV (except IT works). I wonder why there are two different macros that do the same thing (aside from the "int bugginess" of _BV)?
(4) Looking at the bit macro, I see they do the same thing I was trying to do (cast the TYPE of the value "1").
So, why not use "1ULL" to cover every possibility? Any reason NOT to?
And, what do you mean by using a "template"? I have no idea what that means.
Krupski:
(1) I usually don't need anything 64 bit, but I thought why not give it all the functionality possible?
Note: 64 bit expressions are very expensive with avr-gcc.
The problem is that it forces the compiler's hand. The rest of the expression has to be evaluated in 64 bit. Because the value is a constant, the compiler will typically optimize to a more appropriate size but that may not always be the case.
(3) Wow, I didn't know about the bit macro. It's the same as _BV (except IT works). I wonder why there are two different macros that do the same thing (aside from the "int bugginess" of _BV)?
_BV is included with AVR Libc. It is primarily intended to be used for 8 bit bitmasks.
I don't know why the Arduino folks included bit. I suspect it is left over from Processing.
So, why not use "1ULL" to cover every possibility? Any reason NOT to?
Try printing the value...
Serial.print( (1ULL < 0) );
And, what do you mean by using a "template"? I have no idea what that means.
Don't worry about it. I can't find much if any value in using a template for this problem. bit is the better choice.
Arduino is intended for people who have never programmed. People who have never programmed occasionally do unexpected, even strange, things.
It is important for the Arduino API (e.g. bit) to have well defined behaviour for those (all) occasions. The behaviour may not be useful but it should be well defined. For example, bit could return zero if the parameter is negative. That's not particularly useful but, if someone were to ask why bit(-5) does not seem to work, someone from the forum could easily respond, "well, you see, bit(negative) always returns zero because bit(negative) does not make sense."
The alternative requires the person providing support to first determine how bit(-5) behaves then decide if that behaviour matches the symptoms and then be in a position to help.
There's no such thing as _BV (-1)!
The problem is that, as far as the compiler is concerned, there is such a thing.
Personally, I would prefer bit(negative) / _BV(negative) to fail at compile time for constants and return zero for variables.