C - Why compare constants with & instead of switch/if? - c

I am reading the OpenSL documentation for Android. Quoting the following document: http://mobilepearls.com/labs/native-android-api/ndk/docs/opensles/
"Callback handlers should be prepared to be called more or less frequently, to receive additional event types, and should ignore event types that they do not recognize. Callbacks that are configured with an event mask of enabled event types should be prepared to be called with multiple event type bits set simultaneously. Use "&" to test for each event bit rather than a switch case."
Checking the official specification of OpenSL (https://www.khronos.org/registry/sles/specs/OpenSL_ES_Specification_1.0.1.pdf), there are these 3 constants defined I am interested in:
SL_PREFETCHSTATUS
#define SL_PREFETCHSTATUS_UNDERFLOW ((SLuint32) 0x00000001)
#define SL_PREFETCHSTATUS_SUFFICIENTDATA ((SLuint32) 0x00000002)
#define SL_PREFETCHSTATUS_OVERFLOW ((SLuint32) 0x00000003)
If I understood correctly, the quote above says to compare using &, like this:
if(status & SL_PREFETCHSTATUS_UNDERFLOW) doSomething_1();
if(status & SL_PREFETCHSTATUS_SUFFICIENTDATA) doSomething_2();
if(status & SL_PREFETCHSTATUS_OVERFLOW) doSomething_3();
Instead of a switch case:
switch(statusCode){
case(SL_PREFETCHSTATUS_UNDERFLOW): doSomething_1(); break;
case(SL_PREFETCHSTATUS_SUFFICIENTDATA): doSomething_2(); break;
case(SL_PREFETCHSTATUS_OVERFLOW): doSomething_3(); break;
}
Now, I don't understand why that is exactly. Can anyone explain me the reason?
PS: If the constants were defined in multiples of 2, like this:
#define SL_PREFETCHSTATUS_UNDERFLOW ((SLuint32) 0x00000001)
#define SL_PREFETCHSTATUS_SUFFICIENTDATA ((SLuint32) 0x00000002)
#define SL_PREFETCHSTATUS_OVERFLOW ((SLuint32) 0x00000004)
It would make sense, but the specification defines the last constant as 0x00000003 instead of 0x00000004, so I am lost.

That comment is in reference to the event constants. What you're looking at are not event constants, but rather status constants. Event constants would be for example:
#define SL_PLAYEVENT_HEADATEND ((SLuint32) 0x00000001)
#define SL_PLAYEVENT_HEADATMARKER ((SLuint32) 0x00000002)
#define SL_PLAYEVENT_HEADATNEWPOS ((SLuint32) 0x00000004)
#define SL_PLAYEVENT_HEADMOVING ((SLuint32) 0x00000008)
#define SL_PLAYEVENT_HEADSTALLED ((SLuint32) 0x00000010)
You can see these are bitmask values and could be combined. Since they can be combined you need to compare the individual bits rather than the whole value to ensure you correctly match against the events you're interested in.

The documentation makes it clear:
Callbacks that are configured with an event mask of enabled event types should be prepared to be called with multiple event type bits set simultaneously.
This means that despite the flags not being bitwise, there still remains the possibility that multiple flags are set. The other flags being set might not necessarily be publicly-defined, but could be private, reserved or otherwise undocumented but still necessary for the system to function.
...so using a switch is not a good idea because then this fails:
SLuint32 statusCode = SL_PRIVATE_RESERVED_INTERNAL_USE_ONLY | SL_PREFETCH_STATUS_UNDERFLOW;
switch( statusCode ) {
case SL_PREFETCH_STATUS_UNDERFLOW:
// this code will never be executed
break;
}

Using & does bitwise comparison. So a & b gives a non-zero results if any of the bits are set in both a and b. That is not the same as comparing the values (for a given non-zero value of a, there are multiple values of b that can give a match).

Related

Building an Array of #define Directives

I have some microcontroller code that uses some header files where GPIO pins are defined like this:
#define PA3 GPIO(GPIO_PORTA, 3)
Using the IDE, I can navigate to the implementation of GPIO and I find this:
#define GPIO(port, pin) ((((port)&0x7u) << 5) + ((pin)&0x1Fu))
Where pin is defined as:
const uint8_t pin
and port is an enum defined as:
enum gpio_port { GPIO_PORTA, GPIO_PORTB, GPIO_PORTC, GPIO_PORTD, GPIO_PORTE }
I would like to create an array of all the GPIO defins (PA3, PA4, etc.) that can be indexed by an integer passed over a serial port.
I tried the following:
GPIO knavePinList[] = {PA3, PA4, PA21, PB4, PHY_RESET_PIN, PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, PD8, PD9};
But this obviously doesn't work as GPIO is not a recognized C-type, but in fact a macro. While trying to build, I receive this error message:
unknown type name 'GPIO'
Is it even possible for me to declare an array of macros? If so, how would I note the type for what I'm working with?
Thanks.
#define statements perform text replacement, they have no inherent type. As you noted, GPIO is not a valid type, it's a macro that appears to calculate pin numbers/addresses (actually GPIO is undefined, while GPIO(a,b) is the macro).
If you want to store an array of many of these, then you need to know what actual type they all evaluate to. Given that the GPIO macro returns a sum of a port and a pin value, where port is an enum, whose underlying type is int (technically, it's an implementation specific integral type - see What is the underlying type of a c++ enum?) and pin is a uint8_t, the actual type of your array values would also be an integer type - which one specifically depends on your implementation and the range of possible values.
The array you post is perfectly legal, I think you have not tested it. Anyway, it is best to ask with a testable example, (see How to create a Minimal, Complete, and Verifiable example) but the code:
GPIO knavePinList[] = {PA3, PA4, PA21, PB4, PHY_RESET_PIN, PD0, PD1, PD2, PD3, PD4, PD5, PD6, PD7, PD8, PD9};
will produce a perfectly legally initialized array of integers, with the bitwise values of the constants you have expanded from the macros. Try to use
cpp source.c | more
to see how the array declaration is actually expanded. By the way, you have another, different problem in your code... you are using the same identifier, GPIO, to indicate the GPIO macro name, and the type of the array elements, so when the macro processor encounters it, it sees no parameters, which is not how you have #defined it, and complaints about a two parameter macro GPIO called with no parameters at all.
You have to test your code... and send 1. what you expect... and 2. what you get instead... because the error should be evident, if you had simply stopped to read it.
A solution to your problem is to rename the macro GPIO to GPIO_BITS for example... and then change all the definitions:
#define GPIO_BITS(port, pin) ((((port)&0x7u) << 5) + ((pin)&0x1Fu))
...
#define PA3 GPIO_BITS(GPIO_PORTA, 3)
so when you encounter the array definition, the type name is not tried to expand as a macro.
No, you cannot create an array of macros like that.
If you want to execute a particular macro based on an input, you will need to use an if-else or switch statement. If the input is an integer, you could do something like:
switch( input )
{
case 0: PA3; break;
case 1: PA4; break;
case 2: PA21; break;
...
}

Using ENUMs as bitmaps, how to validate in C

I am developing firmware for an embedded application with memory constraints. I have a set of commands that need to processed as they are received. Each command falls under different 'buckets' and each 'bucket' gets a range of valid command numbers. I created two ENUMs as shown below to achieve this.
enum
{
BUCKET_1 = 0x100, // Range of 0x100 to 0x1FF
BUCKET_2 = 0x200, // Range of 0x200 to 0x2FF
BUCKET_3 = 0x300, // Range of 0x300 to 0x3FF
...
...
BUCKET_N = 0xN00 // Range of 0xN00 to 0xNFF
} cmd_buckets;
enum
{
//BUCKET_1 commands
CMD_BUCKET_1_START = BUCKET_1,
BUCKET_1_CMD_1,
BUCKET_1_CMD_2,
BUCKET_1_CMD_3,
BUCKET_1_CMD_4,
//Add new commands above this line
BUCKET_1_CMD_MAX,
//BUCKET_2 commands
CMD_BUCKET_2_START = BUCKET_2,
BUCKET_2_CMD_1,
BUCKET_2_CMD_2,
BUCKET_2_CMD_3,
//Add new commands above this line
BUCKET_2_CMD_MAX,
//BUCKET_3 commands
...
...
...
//BUCKET_N commands
CMD_BUCKET_N_START = BUCKET_N
BUCKET_N_CMD_1,
BUCKET_N_CMD_2,
BUCKET_N_CMD_3,
BUCKET_N_CMD_4,
//Add new commands above this line
BUCKET_N_CMD_MAX,
}cmd_codes
When my command handler function receives a command code, it needs to check if the command is enabled before processing it. I plan to use a bitmap for this. Commands can be enabled or disabled from processing during run-time. I can use an int for each group (giving me 32 commands per group, I realize that 0xN00 to 0xN20 are valid command codes and that others codes in the range are wasted). Even though commands codes are wasted, the design choice has the benefit of easily telling the group of the command code when seeing raw data on a console.
Since many developers can add commands to the 'cmd_codes' enum (even new buckets may be added as needed to the 'cmd_buckets' enum), I want to make sure that the number of command codes in each bucket does not exceed 32 (bitmap is int). I want to catch this at compile time rather than run time. Other than checking each BUCKET_N_CMD_MAX value as below and throwing a compile time error, is there a better solution?
#if (BUCKET_1_CMD_MAX > 0x20)
#error ("Number of commands in BUCKET_1 exceeded 32")
#endif
#if (BUCKET_2_CMD_MAX > 0x20)
#error ("Number of commands in BUCKET_2 exceeded 32")
#endif
#if (BUCKET_3_CMD_MAX > 0x20)
#error ("Number of commands in BUCKET_3 exceeded 32")
#endif
...
...
...
#if (BUCKET_N_CMD_MAX > 0x20)
#error ("Number of commands in BUCKET_N exceeded 32")
#endif
Please also suggest if there is a more elegant way to design this.
Thanks, I appreciate your time and patience.
First fix the bug in the code. As mentioned in comments, you have a constant BUCKET_1 = 0x100 which you then assign CMD_BUCKET_1_START = BUCKET_1. The trailing enums will therefore get values 0x101, 0x102, ... and BUCKET_1_CMD_MAX will be 0x106. Since 0x106 is always larger than 0x20, your static assert will always trigger.
Fix that so that it actually checks the total number of items in the enum instead, like this:
#define BUCKET_1_CMD_N (BUCKET_1_CMD_MAX - CMD_BUCKET_1_START)
#define BUCKET_2_CMD_N (BUCKET_2_CMD_MAX - CMD_BUCKET_2_START)
...
Assuming the above is fixed, then you can replace the numerous checks with a single macro. Not a great improvement, but at least it reduces code repetition:
#define BUCKET_MAX 32 // use a defined constant instead of a magic number
// some helper macros:
#define CHECK(n) BUCKET_ ## n ## _CMD_N
#define STRINGIFY(n) #n
// the actual macro:
#define BUCKET_CHECK(n) \
_Static_assert(CHECK(n) <= BUCKET_MAX, \
"Number of commands in BUCKET_" STRINGIFY(n) "_CMD_N exceeds BUCKET_MAX.");
// usage:
int main (void)
{
BUCKET_CHECK(1);
BUCKET_CHECK(2);
}
Output from gcc in case one constant is too large:
error: static assertion failed: "Number of commands in BUCKET_1_CMD_N exceeds BUCKET_MAX."
note: in expansion of macro 'BUCKET_CHECK'
EDIT
If combining the bug fix with the check macro, you would get this:
#define BUCKET_MAX 32
#define CHECK(n) (BUCKET_##n##_CMD_MAX - CMD_BUCKET_##n##_START)
#define STRINGIFY(n) #n
#define BUCKET_CHECK(n) \
_Static_assert(CHECK(n) <= BUCKET_MAX, \
"Number of commands in BUCKET " STRINGIFY(n) " exceeds BUCKET_MAX.");
int main (void)
{
BUCKET_CHECK(1);
BUCKET_CHECK(2);
}
First of all, preprocessor commands do not work that way. The C preprocessor is able to "see" only names instruced by the #define statement or passes as compiler flags. It is not able to see constants defined as part of an enum or with the const keyword. You should use _Static_assert to validate the commands instead of the preprocessor.
As for the commands, I would suggest to have all the commands numbered in the range 0..0x20:
enum {
BUCKET_1_CMD_1,
BUCKET_1_CMD_2,
...
BUCKET_1_CMD_MAX,
};
enum {
BUCKET_2_CMD_1,
BUCKET_2_CMD_2,
...
BUCKET_2_CMD_MAX,
};
Then you need only a single guard value to check if all the commands are in valid range:
#define MAX_COMMAND 0x20
_Static_assert(BUCKET_1_CMD_MAX <= MAX_COMMAND, "too many bucket 1 commands");
_Static_assert(BUCKET_2_CMD_MAX <= MAX_COMMAND, "too many bucket 2 commands");
To use the commands, bitwise-or them together with the bucket "offset":
enum {
BUCKET_1 = 0x100,
BUCKET_2 = 0x200,
};
...
int cmd = BUCKET_2 | BUCKET_2_CMD_1;

C macros: Conditional code based on parameter value?

Is there a cleaner/simpler way to do this?
The below works OK, but I think it's ugly - I'd like a solution that doesn't need a separate #define for every possible invalid value passed as "port".
#define _port_A_config_digital(mask) // do nothing; this port is always digital
#define _port_B_config_digital(mask) AD1PCFGSET = (mask)
#define _port_C_config_digital(mask)
#define _port_D_config_digital(mask)
#define _port_E_config_digital(mask)
#define _port_F_config_digital(mask)
#define _port_G_config_digital(mask)
#define _port_H_config_digital(mask)
#define _port_I_config_digital(mask)
#define _port_J_config_digital(mask)
#define _port_K_config_digital(mask)
#define ConfigDigitalBits(port, mask) _port_##port##_config_digital(mask)
If "port" is anything other than B, I want a null statement.
I'd like to get rid of all the #defines other than the one that does something.
I want to do this because on this MCU all ports other than B are always digital and there's nothing to be done.
But calling ConfigDigitalBits() ought to be a valid thing to do for any port.
You could do something like
#define CONFIG_DIGITAL_BITS(PORT, MASK) \
do { if (PORT == 'B') AD1PCFGSET = (MASK); } while (0)
and trust (or check by reading the assembly) your compiler to evaluate the if condition at compile-time. That is,
CONFIG_DIGITAL_BITS('B', 0x42);
would generate code for only
AD1PCFGSET = 0x42;
and
CONFIG_DIGITAL_BITS('A', 0x42);
would generate no code at all.
The proposed code above has the problem that it ignores errors. For example,
CONFIG_DIGITAL_BITS('Z', 0x42);
would happily compile although there is no port Z. You could assert on this but this will only catch the error at run-time.
Once you got to this, consider getting rid of the macro at whole and use an inline function instead that will also permit constant propagation.
inline void
config_digital_bits(const char port, const unsigned mask)
{
assert(port >= 'A' && port <= 'K');
if (port == 'B')
AD1PCFGSET = mask;
}

Why is this line obfuscated?

In this snippet,
if(((RCC_OscInitStruct->OscillatorType) & RCC_OSCILLATORTYPE_HSI) == RCC_OSCILLATORTYPE_HSI)
{
/* statements */
}
the member OscillatorType could have any of the values, or their combination, defined below.
#define RCC_OSCILLATORTYPE_NONE ((uint32_t)0x00000000)
#define RCC_OSCILLATORTYPE_HSE ((uint32_t)0x00000001)
#define RCC_OSCILLATORTYPE_HSI ((uint32_t)0x00000002)
#define RCC_OSCILLATORTYPE_LSE ((uint32_t)0x00000004)
#define RCC_OSCILLATORTYPE_LSI ((uint32_t)0x00000008)
Why is the if written this way? Why not simply like this?
if(RCC_OscInitStruct->OscillatorType == RCC_OSCILLATORTYPE_HSI)
RCC_OscInitStruct->OscillatorType is a collection of bits packed in an integer value, each bit representing one of the values (RCC_OSCILLATORTYPE_HSE, ...). That's why they come in powers of 2. The code you showed just checks if the bit associated with RCC_OSCILLATORTYPE_HSI is set. It's very probable that bits of other values are also set.
For example if the binary representation of OscillatorType is 0...011, the first and second bit is set, meaning that the RCC_OSCILLATORTYPE_HSE and RCC_OSCILLATORTYPE_HSI values are selected.
It's a very common C idiom and not obfuscated in any way. Those are two very different tests.
if ((RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE_HSI) == RCC_OSCILLATORTYPE_HSI)
says "if the RCC_OSCILLATOR_HSI bit is 1". It doesn't care whether any of the other bits are 0 or 1, whereas
if (RCC_OscInitStruct->OscillatorType == RCC_OSCILLATORTYPE_HSI)
says "if the RCC_OSCILLATOR_HSI bit is 1 AND all the other bits are 0".
Because it may have any of these values at the same time. The & (bitwise AND) operator is serving the purpose of extracting only the value RCC_OSCILLATOR_TYPE_HSI.
As an example, your input may look like this:
010011
While RCC_OSCILLATOR_TYPE_HSI looks like this:
000010
The AND operator with these two values will return 000010, witch exactly equals RCC_OSCILLATOR_TYPE_HSI.
However, if your input looks like this:
110101
The bitwise AND operator between this and RCC_OSCILLATOR_TYPE_HSI will return 0, and the condition will be false.
The if condition is interested only in the second last bit of RCC_OscInitStruct->OscillatorType. So RCC_OSCILLATORTYPE_HSI is used as a mask and then compared to itself.
If you see all the constants, first one is all zeroes where as the others have its set bit at successive positions.
Now, doing & with any of these constants can tell you whether its corresponding bit is set in the said parameter.
If you want to set all of the possible values, you would be doing:
RCC_OscInitStruct->OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSE | RCC_OSCILLATORTYPE_LSI;
Why comparison using ==?
That's not required and makes the code cluttered. I think that the programmer wanted to bring uniformity when testing for RCC_OSCILLATORTYPE_NONE.
The programmer can't test for RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE_NONE because that would evaluate to zero. You are either forced to negate the condition just for this check.
An example:
#include <stdio.h>
#include <stdint.h>
#define RCC_OSCILLATORTYPE_NONE ((uint32_t)0x00000000)
#define RCC_OSCILLATORTYPE_HSE ((uint32_t)0x00000001)
#define RCC_OSCILLATORTYPE_HSI ((uint32_t)0x00000002)
#define RCC_OSCILLATORTYPE_LSE ((uint32_t)0x00000004)
#define RCC_OSCILLATORTYPE_LSI ((uint32_t)0x00000008)
int main(void)
{
/* set HSI and HSE */
uint32_t flags = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI;
if (flags == RCC_OSCILLATORTYPE_HSI) {
puts("flags = HSI");
}
if ((flags & RCC_OSCILLATORTYPE_HSI) == RCC_OSCILLATORTYPE_HSI) {
puts("HSI is set in flags");
}
return 0;
}
Output:
HSI is set in flags
To begin with, == is not equivalent with &. Because == looks at the whole 32 bit register, including any crap you aren't interested in. While & just looks at the relevant parts.
And the & is simple binary arithmetic for bitwise AND. In my opinion, you need to understand binary numbers before even enrolling your first programmer course, but maybe that's just me.
Anyway, given that you actually understand what bitwise AND does, it would have made more sense if you had code like
#define RCC_OSCILLATORTYPE ((uint32_t)0x0000000F) // mask
#define RCC_OSCILLATORTYPE_NONE ((uint32_t)0x00000000)
#define RCC_OSCILLATORTYPE_HSE ((uint32_t)0x00000001)
#define RCC_OSCILLATORTYPE_HSI ((uint32_t)0x00000002)
#define RCC_OSCILLATORTYPE_LSE ((uint32_t)0x00000004)
#define RCC_OSCILLATORTYPE_LSI ((uint32_t)0x00000008)
...
(RCC_OscInitStruct->OscillatorType & RCC_OSCILLATORTYPE) == RCC_OSCILLATORTYPE_HSI
Maybe this is what the programmer of that code intended, but they didn't quite manage to bring the code all the way there.

Array in #define

I am trying to achieve something like this:
#define MACRO(x) {PORTB=0,PORTC=0,PORTD=0}
MACRO(0); //This would get replaced by PORTB=0;
MACRO(1); //PORTC=0;
MACRO(2); //PORTD=0;
I want to create a "macro array". I would pass in an index to it and it would return the right code.
Is this possible?
EDIT:
If it helps, PORTB, PORTC and PORTD are all #defines.
It can be done using the preprocessor, but it is arguably ugly.
#define MACRO_CASE0 PORTB = 0
#define MACRO_CASE1 PORTC = 0
#define MACRO_CASE2 PORTD = 0
#define MACRO(X) MACRO_CASE##X
Also have a look at the Boost.Preprocessor library. (It works for both C and C++.)
Update: After the discussion with Jonathan Leffler (see below) I feel an obligation to update the answer with an exhortation for new C programmers not to abuse the (powerful but dirty) technique shown above.
If you – as the OP requested – want to pass in an index to it and it would return the right code, then you'll need to resort to preprocessor programming. However, if all you want to do is execute different code based on some condition and want this to have no run-time overhead if the condition is a compile-time constant, then the following approach is not only much cleaner but also more flexible as it allows passing run-time values too.
/* '#include' this definition in any file where you want to use it. */
static inline void
do_the_right_thing(const int selector)
{
switch (selector)
{
case 0:
PORTB = 0;
break;
case 1:
PORTC = 0;
break;
case 2:
PORTD = 0;
break;
default:
assert(!"cannot do the right thing: invalid selector");
}
}
Now, in your code, if you write
do_the_right_thing(1); /* selector is a compile-time constant */
a decent compiler with appropriate optimizations enabled will generate no overhead compared to using a macro. However, you can also write
do_the_right_thing(rand() % 3); /* selector is a run-time expression */
and the compiler will insert some fast switching code to select the appropriate operation at run-time.
This would do the task, but it doesn't extend or generalize very gracefully:
#define MACRO(x) (((x) == 0) ? PORTB=0 : ((x) == 1) ? PORTC=0 : PORTD=0)

Resources