What purpose does the enum name serve? - c

An enum is a "named collection of constants": enum MyType_e {A, B, C};
Those constants are declared in the parent scope of the enum i.e. if the enum is declared in file scope, and is unnamed, it is equivalent to a series of e.g.#define A 0 statements
The underlying type for enum constants is always int i.e. int var = A is fully legal, although var is not of type MyType_e
So what purpose does the enum name serve?
EDIT
As per the comments below, my understanding of enums appears to be quite flawed. An enum has nothing to do with #define statements. Enums are resolved at compile time, and are typed.

Using the enum type conveys intent.
Suppose you have a function that takes an enum constant as an argument.
void foo(enum MyType_e e);
is self-documenting about what valid inputs are but:
void foo(int e);
is not. Moreover, the compiler may issue warnings if you attempt to pass incompatible values for the enum type. From Annex I ("Common warnings") of the ISO C99 specification:
An implementation may generate warnings in many situations.... The following are a few of the more common situations.
[...]
A value is given to an object of an enumeration type other than by assignment of an enumeration constant that is a member of that type, or an enumeration variable that has the same type, or the value of a function that returns the same enumeration type (6.7.2.2).
Some compilers (for example, gcc) might even generate warnings if you use switch on an enum type but neglect to handle all of its constants and don't have a default case.

While you can perfectly say
int var = A
the variant
enum mytype var = A
is better for documentatory reasons.

The answers above are good and correct, I just want to add that certain debuggers, are able to show the enum name when hovering or mointoring an enum type variable. This really helps clarity, especially when enums are used for states in state machine implementation.

Related

Avoid name collisions with enum in C (C99)

enum elements' names are susceptible to overlap/collide with both other enum elements names, variable names, etc...
enum Fruit
{
apple,
orange
};
typedef enum Fruit Fruit;
enum Color
{
red,
orange // <-- ERROR
};
typedef enum Color Color;
char apple='a'; // <-- ERROR
Is there a C99 compliant solution to avoid collision other than prefixing every enum element name?
Side note: this question has already an answer for C++
How to avoid name conflicts for two enum values with the same name in C++?
I'm looking for a C99 solution.
In C, there is no solution other than prefixing the names of the enum values.
As pointed out in the OP, C++ has a number of mechanisms, of which enum class is probably indicated for modern code. However, in practice the result is the same: you end up prefixing the name of the enum element with the name of the enum. Arguably, Fruit::orange is tidier than FruitOrange, but really it makes little difference to my eyes.
In some parallel universe, it would be great to have a language in which you could write:
Fruit selected = orange;
and have the compiler deduce the namespace of the constant on the right-hand side. But I don't see how that language could be C. C doesn't have namespaces in that sense, and even if it did, the type system only allows conversions; you cannot condition the syntax of the RHS of an operator based on the LHS (and I use the word syntax deliberately, because name lookup is a syntactic property in C).
Even if you did have some language hack which sometimes implictly inserted an enum namespace, you would still need the explicit prefix on any comparison, because
if (apple > orange)
does not have a context in which deduction could take place, even though the fact that enum values in C are all of type int does make FruitApple and FruitOrange comparable.

Why does an anonymous enum fails MISRA C 2012 rule 10.3 and a named enum doesn't?

In question:
Why do I have to cast an enum element when assigning it to a same enum variable type in C?
I was having problems with this code for failing the MISRA C 2012 rule 10.3 that states:
The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category
The code is this:
typedef enum
{
FLS_PROG_SUCCESS,
FLS_PROG_FAIL,
FLS_ERASE_SUCCESS2U,
FLS_ERASE_FAIL,
FLS_READ_SUCCESS,
FLS_READ_FAIL,
FLS_FORMAT_SUCCESS,
FLS_FORMAT_FAIL
}FLS_JobResult_t;
void Foo(void)
{
FLS_JobResult_t ProgramStatus;
/* Then I try to initialize the variable value */
ProgramStatus = FLS_PROG_SUCCESS;
...
}
And I accepted an answer that suggest that the tool may be flawed. I still do believe that but fooling around trying to fix that I put a name to the typedef enum declaration which now is:
typedef enum FLS_JobResult_tag
{
FLS_PROG_SUCCESS,
FLS_PROG_FAIL,
FLS_ERASE_SUCCESS2U,
FLS_ERASE_FAIL,
FLS_READ_SUCCESS,
FLS_READ_FAIL,
FLS_FORMAT_SUCCESS,
FLS_FORMAT_FAIL
}FLS_JobResult_t;
And as far as I know both are exactly the same. But then, surprise! The error went away! The rules checker is no longer flagging that as an error!!
Then doing some research I found this two questions:
What are the differences between these two typedef styles in C?
and
What's the difference between these two enum declarations - C?
And I realized that there are subtle differences between an anonymous enum and a named enum. But nothing that makes clear what could be the reason for the rule checker to complaint about one form of the other.
So the question is: What is the difference from an anonymous enum vs named enum that may break rule 10.3 from MISRA c 2012?
Both examples are compliant, and both for the same reasons: they are not assigning an object of a different essential type.
Let's clear up the confusion.
C grants developers/compilers a lot of freedom in its type system, but it also can lead to unintended results, with the potential for loss of value, sign or precision. MISRA-C:2012 helps enforce safer typing with its essential type model, which provides the rational basis for its rule definitions in controlling the use of type conversions and promoting awareness of implementation specific behavior (the 10.x Rules).
The essential type model replaces the MISRA-C:2004 standard’s “underlying type” model (which caused a lot of programmer grief enforcing unnecessary casts for one reason).
I suspect your tool is confused, and/or partially stuck with the older model.
The essential type rules that pertain to enumerations recognizes two different programming uses:
an object of an enum type intended to be distinct from an object with a
different enum type.
enums are a common way of holding a set of integer constants.
The C standard does not give a way of distinguishing between these uses. Therefore MISRA-C:2012 added the following distinct essential types of enumeration (while not affecting C behavior):
Named enum type - enumeration defined in this is
identified either by a tag or a typedef or used in the definition of
any object, function or type; A cast must be used if the integer
value of the enumeration constant is required.
Anonymous enum type - an enumeration which is not used in the
definition of any object, function or type. This will typically be
used to define a set of constants, which may or may not be related,
but avoids the need for casting.
An example of an anonymous enum type:
enum {D = 10, E = 20, F = 30};
Both your examples are named enum types (and they are compliant because they are the same essential type). Other examples are:
enum JOHN {A, B, C};
enum PAUL {E, F, G} PAUL;
Thus, an example of a real 10.3 violation would be:
enum PAUL bar = B;
Reference: MISRA-C:2012 Appendix D.5 "The essential type of enumerations” amplifies this very well with other examples.
With lside (type is anonymous enumeration) = rside (type is anonymous enumeration) the left and right do not know it is the same anonymous enumeration - hence potential problems.
With lside (type is named enumeration) = rside (type is _same_ named enumeration) - all is OK it is known the same enumeration is used.
The real "bug" is actually in the C standard (6.7.2.2). An enumeration constant is guaranteed by C to be of type int, but an enumeration variable may be of a number of different types, for example char.
As for which essential type that is used for enumeration constants and enumeration variables, it is described in MISRA-C:2012 appendix D.6. The enumeration constants in your code are considered to be of the same essential type as the named enum type.
So the tool is incorrect and should not issue a diagnostic.
it is (almost) always a bad idea to typedef an enum.
Much better to write it as follows:
enum FLS_JobResult_t
{
FLS_PROG_SUCCESS,
FLS_PROG_FAIL,
FLS_ERASE_SUCCESS2U,
FLS_ERASE_FAIL,
FLS_READ_SUCCESS,
FLS_READ_FAIL,
FLS_FORMAT_SUCCESS,
FLS_FORMAT_FAIL
};
void Foo(void)
{
enum FLS_JobResult_t ProgramStatus;
/* Then I try to initialize the variable value */
ProgramStatus = FLS_PROG_SUCCESS;
}

Using lambda captured constexpr value as an array dimension

GCC and Clang do compile the following code:
void Test()
{
constexpr int Size = 3;
auto Lambda = [Size]{ int Dim[Size]; };
}
However, VisualStudio 2015 CTP 6 does not. Nevertheless, all 3 compilers are happy with this code:
void Test()
{
static constexpr int Size = 3;
auto Lambda = []{ int Dim[Size]; };
}
Which snippet is actually doing it in the correct way? What does the C++ standard say?
This question is related to Lambda capturing constexpr object
C++11 [expr.prim.lambda]/12
If a lambda-expression odr-uses this or a variable with automatic storage duration from its reaching scope, that entity shall be captured by the lambda-expression.
and /17
Every id-expression that is an odr-use of an entity captured by copy is transformed into an access to the corresponding unnamed data member of the closure type. [ Note: An id-expression that is not an odr-use
refers to the original entity, never to a member of the closure type. [...]
— end note ]
So we don't even need to capture Size in the first example (where it is not static), since reading from that variable is not an odr-use since it can appear in a constant expression and the lvalue-to-rvalue conversion is immediately applied to it, [basic.def.odr]/2
A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression and the lvalue-to-rvalue
conversion is immediately applied.
(It is not clear to me if the array bounds require an l-t-r conversion, though.)
The same applies when capturing Size by reference, or when capturing Size explicitly (by copy) but not odr-using it: the use of the id-expression Size within the lambda accesses the constexpr variable declared in Test, not any captured member (for capture-by-copy: IFF the access does not constitute an odr-use).
C++14 [expr.prim.lamda]/12 adds some wording for polymorphic lambdas that is irrelevant here, and moves /17 to /18. The rules for odr-use are more complicated, but I'd argue it's not an odr-use for the same underlying reason (reading a compile-time constant).

Better enums in C (Arduino)

I thought the below was a neat way to implement enums in C.
struct states
{
enum
{
waitPackage,
waitReference,
waitData
};
}state;
This adds some type safety and I can also acces each member through state.XXX which I think is a lot more neat than prepend all the names of the enum items, and access the members in a fashion like state_XXX. Or what do you think, have I missed something?
However, I cant use the enum above in a switch-case statement as the compiler says that state isn't a constant.
Is there a way to tell the compiler that I don't intend to change the members of the enum ot it could be used in switch-case? Or another way to accomplish what I would like here?
In a C++ I solved it by placing the enums in namespaces but thats a not an option here.
Types in C are always global and never nested. So there is no way to have scoped constants.
Thus the :: notation is not allowed in C, it is not part of the syntax. E.g your constants as waitPackage are visible as such everywhere.

Objective-C / C giving enums default values

I read somewhere about giving enums default values like so:
typedef enum {
MarketNavigationTypeNone = 0,
MarketNavigationTypeHeirachy = 1,
MarketNavigationTypeMarket = 2
} MarketNavigationLevelType;
.. but i can't remember the value of doing this. If i don't give them default values - and then someone later on reorders the enum - what are the risks?
If i always use the enum name and don't even refer to them by their integer value, is there any risks?
The only possible problem i can think of is if i'm initialising an enum from an int value from a DB - and the enum is reordered - then the app would break.
That are not default values, you are giving them the values they will always have.
If you wouldn't initialize them explicitly, the first enumerators value is zero. For all others, if there is no initializer, their value is the value of the previous enumerator increased by one.
There are two reasons for giving them explicit values:
you don't want them to have the values they'd have otherwise
you want to make it clear what value they have (for you or other developers)
If you always refer to them by their name and never explicitly use an integral value for comparison or assignment, explicitly giving them a value is not needed.
In general this only matters if the enum is exposed to some kind of external API or it is going to be used to exchange data via data files or other means. If the enum is only every used within your app and nowhere else then the actual values don't matter.

Resources