C switch statement and enum explicit cast - c

Saw a lot of similar questions but none answer my question here:
Suppose I have an enum Property:
enum
{
PROP_A = 1,
PROP_B,
N_PROPERTIES
} Property;
When I try to use it in a switch statement like this:
// file test.c
enum
{
PROP_A = 1,
PROP_B,
N_PROPERTIES
} Property;
int main(void)
{
int a = 0;
switch ((Property) a)
{
case PROP_A:
break;
case PROP_B:
break;
default:
break;
};
return 0;
}
The compiler throws this error:
test.c: In function ‘main’:
test.c:11:20: error: expected ‘)’ before ‘a’
11 | switch ((Property) a)
| ~ ^~
| )
What is wrong with this code? For reference, in the GObject documentation they have this snippet:
typedef enum
{
PROP_FILENAME = 1,
PROP_ZOOM_LEVEL,
N_PROPERTIES
} ViewerFileProperty;
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
static void
viewer_file_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
ViewerFile *self = VIEWER_FILE (object);
switch ((ViewerFileProperty) property_id)
{
case PROP_FILENAME:
g_free (self->filename);
self->filename = g_value_dup_string (value);
g_print ("filename: %s\n", self->filename);
break;
case PROP_ZOOM_LEVEL:
self->zoom_level = g_value_get_uint (value);
g_print ("zoom level: %u\n", self->zoom_level);
break;
default:
/* We don't have any other property... */
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
Which is essentially the same thing. Therefore it must be possible. What's wrong with my version?

In this declaration
enum
{
PROP_A = 1,
PROP_B,
N_PROPERTIES
} Property;
you declared an object Property of an unnamed enumeration type.
So in the switch statement
switch ((Property) a)
you are using a syntactically incorrect expressions with two objects Property and a.
It seems you mean
typedef enum
{
PROP_A = 1,
PROP_B,
N_PROPERTIES
} Property;
Pay attention that you may just write
switch ( a )
In C enumerators have the type int. That is these enumerators PROP_A, PROP_B, N_PROPERTIES all have the type int. So the casting that you tried to apply (if the enumeration would be declared correctly) is redundant.

Suppose I have an enum Property:
enum
{
PROP_A = 1,
PROP_B,
N_PROPERTIES
} Property;
Your code does not define Property as an enum type. It declares it as a variable whose type is an untagged enum type. Typecast operators must be constructed from types, not variables, so (Property) a is invalid.
That cast is also unnecessary. One way to solve the problem would be simply to drop it:
switch (a) {
case PROP_A:
break;
case PROP_B:
break;
default:
break;
}
Alternatively, if you mean to define Property as a type alias, then that is the function of typedef:
typedef enum {
PROP_A = 1,
PROP_B,
N_PROPERTIES
} Property;
Personally, however, I am not a fan of typedef. It has a few good uses, but it tends to be applied far beyond those. If I wanted to declare an enum type that I could reference apart from its declaration, then I would include a tag:
enum property {
PROP_A = 1,
PROP_B,
N_PROPERTIES
};
int main(void) {
int a = 0;
switch ((enum property) a) {
case PROP_A:
break;
case PROP_B:
break;
default:
break;
}
return 0;
}
(The cast is included for demonstrative purposes -- it's still unnecessary.)

You need to add typedef before enum to identify Property as a type. In the other example you provided for comparison, typedef is used.

Related

Passing a typedef enum as a parameter in c throwing error

I'm programming in a cortex m3 for the LPC1343 microcontroller. When I compile my code I get an error in the line SetLed((eLeds_t *)h1, false); it says Error[Pe018]: expected a ")" as if this the cast that I do wasn't good enough I guess.
Follows the enum type def declaration and the :
#ifndef _LEDS_h
#define _LEDS_h
#ifndef bool
typedef unsigned char bool;
# define true 1;
# define false 0;
#endif // ifndef bool
enum eLeds
{
noled, p1l, p1r, p2l, p2r, h1, h2
};
typedef enum eLeds eLeds_t;
void SetLed(eLeds_t led, bool action)
{
switch (led)
{
case p1l:
GPIOSetValue(PORT2, 5, action);
break;
case p1r:
GPIOSetValue(PORT2, 8, action);
break;
case p2l:
GPIOSetValue(PORT0, 9, action);
break;
case p2r:
GPIOSetValue(PORT0, 8, action);
break;
case h1:
GPIOSetValue(PORT0, 5, action);
break;
case h2:
GPIOSetValue(PORT0, 7, action);
break;
}
}
void leds_init(void)
{
GPIOSetDir(PORT2, 5, 1); // p1l
GPIOSetDir(PORT2, 8, 1); // p1r
GPIOSetDir(PORT0, 9, 1); // p2l
GPIOSetDir(PORT0, 8, 1); // p2r
GPIOSetDir(PORT0, 5, 1); // h1
GPIOSetDir(PORT0, 7, 1); // h2
LPC_IOCON->PIO2_5 &= ~0x07;
LPC_IOCON->PIO2_8 &= ~0x07;
LPC_IOCON->PIO0_9 &= ~0x07;
LPC_IOCON->PIO0_8 &= ~0x07;
LPC_IOCON->PIO0_5 &= ~0x07;
LPC_IOCON->PIO0_7 &= ~0x07;
eLeds_t value = h1;
SetLed(&value, false);
}
#endif // ifndef _LEDS_h
You are casting the enum (probably a value like 0, 1, 2...) to a pointer and then the method you pass that to expects to dereference the pointer and use what it is pointing at? Even if the passing syntax was right (and it does look syntactically ok - if not sensible), it will invoke undefined behavior on the dereference.
This will work:
void leds_init(void)
{
eLeds_t value = h1;
SetLed(&value, false);
}
The fact that all of this is in a .h is WRONG. If you include it from multiple places your going to have multiply defined symbols.
Your handling of bool is WRONG. #ifndef bool will only pick up if bool has been hash defined. It won't pick up a typedef-ed bool. Find out what the compiler has and use that. In C TRUE and FALSE are normally defined (stdio.h?) - use those. Or better yet not a bool. Why not an action enum "PERFORM_ACTION" and "SKIP_ACTION"? That way you don't need to remember what that bool was supposed to be...

Why do I need this strange cast for enum arithmetics?

I have this piece of code:
typedef enum myEnum_e
{
VAL0,
VAL1
} myEnum;
void func(void)
{
myEnum val = (myEnum) 0;
while(/*Do something*/)
{
val = val + ((myEnum)1); // <= Warning here
}
}
This piece of code produces the warning:
enumerated type mixed with another type
To clean this I ended up with:
void func(void)
{
myEnum val = (myEnum) 0;
while(/*Do something*/)
{
val = ((myEnum) val + 1); // <= NO Warning here
}
}
Could someone tell why the first form is incorrect?
I feel like the second is less meaningful than the first one.
I mean I would prefer to read:
Add 1, considered as a myEnum value, to val (and store the result in val)
Than
Store in val val + 1 considered as a myEnum value
Note: This is a TI C28x compiler (for TI C2000 MCUs).
Edit:
My real application is to define a custom UART communication for embedded software.
So here is what I have done:
typedef enum e_frame
{
FRAME_A,
FRAME_B,
FRAME_C,
FRAME_COUNT
} frame_e;
typedef enum e_frameId
{
FRAMEID_A = 0x0A,
FRAMEID_B = 0x42,
FRAMEID_C = 0xFF
} frameId_e;
const frameInfo_s FramesInfo[FRAME_COUNT] =
{
[FRAME_A] =
{
.id = MCM_FRAMEID_A,
// And other stuff
},
[FRAME_B] =
{
.id = MCM_FRAMEID_B,
// And other stuff
},
[FRAME_C] =
{
.id = MCM_FRAMEID_C,
// And other stuff
}
}
Finally the the ID to frame_e function:
frame_e UAR_FrameId2Frame(frameId_e id)
{
frame_e frame = (frame_e) 0;
while(FramesInfo[frame].id != id && frame < FRAME_COUNT)
{
frame = (MCM_frames_e)(frame + 1);
}
return frame;
}
I don't get any warnings here:
#include <stdio.h>
typedef enum myEnum_e
{
VAL0,
VAL1
} myEnum;
int main (int argc, char *argv[]) {
myEnum val = 0;
while( 1 /*Do something*/)
{
val = val + 1;
}
return 0;
}
Compiler: GCC 4.2.1
Compile command: gcc -Wall -pedantic x.c
It's a good thing that you are getting a warning.C is not a strictly typed language so you don't get errors when mixing types that can be coerced into one another. But mixing types has the potential to cause subtle runtime errors. So, although internally enums and integers are same types, you shouldn't be mixing them. You should consider using an enum increment variable initialized to 1.
First of all, having code with a lot of casts is not very pleasant to read, but well, that's just a matter of taste.
If you plan to do arithmetic you might want to explicitly define values for the enums. It's risky to do this anyway, because you could end up with an out-of-range values.
What if you add 3 to your VAL0?
Think about it, what does that mean? You've declared an enum, but the value that you now got is not a valid enum anymore. The reason to use an enum is mostly that you want to limit the number of possible values for an ordinal.
In your situation it makes more sense to have constants like VAL0 and VAL1.
Or, if all you needed was to iterate over your enum, you could do this:
typedef enum myEnum_e
{
VAL0,
VAL1,
// ...
VAL66
} myEnum;
for(int i=VAL0; i<=VAL66; i++) {
// do something here
}

Verify that all set values of an enum are distinct

I just recently found out that when setting values of variables of an enum, several variables can have the same value. For example, the following code is perfectly correct:
enum my_enum
{
A = 3,
B = 4,
C = 3,
D = 5
};
However, in my framework, I have to set manualy each variable, since it is used to communicate error codes to other systems. I cannot change the value of an error code without asking for the other teams to modify it as well.
I regrouped all error codes into an enumeration to be sure we do not reuse the same error code for different reasons (which was the case before). But now, nothing stops anyone to reuse the same value for different errors.
Is there a way I can make the compiler return an error if I assign the same value to different names in my enum?
I can compile with either gcc or clang.
A switch statement cannot have two cases with the same value. So you can have a switch somewhere. Make it with no default: case and gcc will warn you that a member of the enum is not handled in the switch statement if you add a new value. If two values of the enum are the same, compilation will fail.
Some examples:
typedef enum {
ERR_NONE = 0,
ERR_SAME = 0
} err_t;
volatile err_t e = ERR_NONE;
int main( int argc, char* argv[] )
{
switch( e )
{
case ERR_NONE:
break;
case ERR_SAME:
break;
}
return 0;
}
with gcc -Wall switch.c gives:
switch.c: In function 'main':
switch.c:16:9: error: duplicate case value
case ERR_SAME:
^
switch.c:13:9: error: previously used here
case ERR_NONE:
^
and...
typedef enum {
ERR_NONE = 0,
ERR_NEXT,
ERR_MISSING,
} err_t;
volatile err_t e = ERR_NONE;
int main( int argc, char* argv[] )
{
switch( e )
{
case ERR_NONE:
break;
case ERR_NEXT:
break;
}
return 0;
}
with gcc -Wall switch-missing.c gives:
switch-missing.c: In function 'main':
switch-missing.c:12:5: warning: enumeration value 'ERR_MISSING' not handled in switch [-Wswitch]
switch( e )
^

how to search in enum type in C

i have following code:
typedef enum Types{
Type_1, Type_2, Type_3
} MyTypes;
typedef union Tree{
struct {
int MyType;
}structAccessor;
} MyTree;
and i'm creating trees like this:
MyTree* node(MyTypes MyType).......//folowwing is unnecessary
and i would like to know how i can find the type of my tree, something like this:
if(node->structAccessor.MyType == MyTypes[2]) //if MyType is Type_2, i want to compare this, thanks so much
enums in C are always of type int.
You can test it against any int like
if (node->structAccessor.MyType == Type_1)
Though they are commonly used in switch statements
switch (node->structAccessor.MyType) {
case Type_1:
...
case Type_2:
...
case Type_3:
...
default: // error
}

C programming lookup table

After some help as have some code which works but trying to fully understand a small section which uses a lookup table as part of a state machine. The state machine I understand and have been using for a tutorial I am writing found here http://coder-tronics.com/state-machine-tutorial-pt1
Instead of using more switch case statements inside the UponExit, UponEnter and ActionWhileInState, someone suggested using this method which I like but don't fully understand.
Now the part I am unsure about is these lines to do with the typedef and lookup table
typedef void (* const voidFunc)(void);
voidFunc UponEnter[S_MAX] = {hEnter_OFF, hEnter_ON, hEnter_PROCESS};
voidFunc ActionWhileInState[S_MAX] = {hInState_OFF, hInState_ON, hInState_PROCESS};
voidFunc UponExit[S_MAX] = {hExit_OFF, hExit_ON, hExit_PROCESS};
I looked up typedef and lookup tables and have a basic understanding, but was hoping someone could give a brief walk through of how this works in this case?
The full part of code this relates to is below for completeness.
enum states { S_OFF, S_ON, S_PROCESS, S_MAX };
enum events { E_OFF, E_ON, E_START, E_MAX};
typedef void (* const voidFunc)(void);
void hEnter_OFF(void); void hEnter_ON(void); void hEnter_PROCESS(void);
void hInState_OFF(void); void hInState_ON(void); void hInState_PROCESS(void);
void hExit_OFF(void); void hExit_ON(void); void hExit_PROCESS(void);
voidFunc UponEnter[S_MAX] = {hEnter_OFF, hEnter_ON, hEnter_PROCESS};
voidFunc ActionWhileInState[S_MAX] = {hInState_OFF, hInState_ON, hInState_PROCESS};
voidFunc UponExit[S_MAX] = {hExit_OFF, hExit_ON, hExit_PROCESS};
enum states StateMachine(enum events event, enum states Current_State)
{
int Next_State = Current_State;
switch ( Current_State )
{
case S_OFF:
switch (event )
{
// A transition to the next state will occur here
case E_ON:
Next_State = S_ON;
break;
default: // Default case placed here to avoid Eclipse warnings as Eclipse expects
break; //to handle all enumerated values
}
break;
case S_ON:
switch (event )
{
// A transition to the next state will occur here
case E_OFF:
Next_State = S_OFF;
break;
case E_START:
Next_State = S_PROCESS;
break;
default: // Default case placed here to avoid Eclipse warnings as Eclipse expects
break; //to handle all enumerated values
}
break;
case S_PROCESS:
switch (event )
{
// A transition to the next state will occur here
case E_OFF:
Next_State = S_OFF;
break;
default: // Default case placed here to avoid Eclipse warnings as Eclipse expects
break; //to handle all enumerated values
}
break;
// The program should never arrive here
default:
break;
}
if (Next_State != Current_State)
{
// Function call for Upon Exit function, it can be omitted but allows extra functionality
UponExit[Current_State]();
// Function call for Upon Enter function, it can be omitted but allows extra functionality
if (Next_State != S_MAX) UponEnter[Next_State]();
}
else // I think ActionWhileInState should only be called when NOT doing a transition!
{
if ( event != E_MAX) ActionWhileInState[Current_State]();
}
return Next_State;
}
Thanks,
Ant
typedef void (* const voidFunc)(void);
is a typedef for a function pointer (for a pointer to a function expecting no parameters and not returning anything to be exact). So your arrays
voidFunc UponEnter[S_MAX] = {hEnter_OFF, hEnter_ON, hEnter_PROCESS};
voidFunc ActionWhileInState[S_MAX] = {hInState_OFF, hInState_ON, hInState_PROCESS};
voidFunc UponExit[S_MAX] = {hExit_OFF, hExit_ON, hExit_PROCESS};
Each hold three different function pointers, one for each state. So a line like
UponExit[Current_State]();
calls the function the pointer UponExit[Current_State] points to which is hExit_OFF if Current_State is 0, hExit_ON if Current_State is 1 or hExit_PROCESS if Current_State is 2.
You could also write the line like that:
(*UponExit[Current_State])();
What looks more complicated but makes clear that UponExit[Current_State] is a function pointer that is "dereferenced" to a call to the function it points to.
Edit:
You have an enum for your states:
enum states { S_OFF, S_ON, S_PROCESS, S_MAX };
Thus, S_OFF == 0, S_ON == 1, S_PROCESS == 2 and S_MAX == 3 (look here)

Resources