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.
Related
I already have, say, a struct smallbox with two primitive variables (int identifier, int size) in it. This smallbox is part of higher structs that are used to build i.e. queues.
Now, I have in a part of my project an issue for which I came up with the solution to expand this smallbox, so it has another piece of information like int costs_to_send_it. While, I am not allowed to change my basis structs, is there a way to expand this struct in some fashion like methods overloading in java or so? Will I still be able to use all operation that I have on my higher structs while having the new struct smallbox with the new attribute inside instead of the old one?
This sentence determines the answer: “[Will] I still be able to use all operation that I have on my higher structs while having the new struct smallbox with color attribute inside instead of the old one?” The answer is no.
If the headers and routines involved were completely separate, there are some compiling and linking “games” you could play—compiling one set of source files with one definition of the structure and another set of source files with another definition of the structure and ensuring they never interacted in ways depending on the structure definition. However, since you ask whether the operations defined using one definition could be used with the alternate definition, you are compelling one set of code to use both definitions. (An alternate solution would be to engineer one source file to use different names for its routines under different circumstances, and then you could compile it twice, once for one definition of the structure and once for another, and then you could use the “same” operations on the different structures, but they would actually be different routines with different names performing the “same” operation in some sense.)
While you could define the structure differently within different translation units, when the structure or any type derived from it (such as a pointer to the structure) is used with a routine in a different translation unit, the type the routine is expecting to receive as a parameter must be compatible with the type that is passed to it as an argument, aside from some rules about signed types, adding qualifiers, and so on that do not help here.
For two structures to be compatible, there must be a one-to-one correspondence between their members, which must themselves be of compatible types (C 2018 6.2.7 1). Two structures with different numbers of members do not have a one-to-one correspondence.
is there a way to expand this struct in some fashion like methods
overloading in java or so?
In method overloading, the compiler chooses among same-named methods by examining the arguments to each invocation of a method of that name. Observe that that is an entirely localized decision: disregarding questions of optimization, the compiler's choice here affects only code generation for a single statement.
Where I still be able to use all operation
that I have on my higher structs while having the new struct smallbox
with color attribute inside instead of the old one?
I think what you're looking for is polymorphism, not overloading. Note well that in Java (and C++ and other the other languages I know of that support this) it is based on a type / subtype relationship between differently-named types. I don't know of any language that lets you redefine type names and use the two distinct types as if they were the same in any sense. Certainly C does not.
There are some alternatives, however. Most cleanly-conforming would involve creating a new, differently-named structure type that contains an instance of the old:
struct sb {
int id;
int size;
};
struct sb_metered {
struct sb box;
int cost;
}
Functions that deal in individual instances of these objects by pointer, not by value, can be satisfied easily:
int get_size(struct sb *box) {
return sb->size;
}
int get_cost(struct sb_metered *metered_box) {
return metered_box->cost;
}
int main() {
struct sb_metered b = { { 1, 17}, 42 };
printf("id: %d, size: %d, cost: %d\n",
b.id,
get_size(&b.box),
get_cost(&b));
}
Note that this does not allow you to form arrays of the supertype (struct sb) that actually contain instances of the subtype, nor to pass or return structure objects of the subtype by value as if they were objects of the supertype.
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;
}
I have several enums that serve as type constants. For example:
enum item_type {
street,
town,
lake,
border,
...
}
The enum values are used in code to designate object types, and are written out to disk as part of data files. This mostly works well, but there is one drawback:
There is no way to remove an enum member (because it is no longer used) without changing the integer values of all subsequent members. So any such change would make the code incompatible with existing data files.
Is there some good technique for avoiding this problem? Maybe some preprocessor trick?
The only solution I can think of is to explicitly set all the integer values. While that would work, it is hard to read and manage for big enums.
Note: This problem comes from the source code of Navit, which uses several such "type enums" (though they are actually hidden behind some macros).
If you want to remove items very rarely, you could do something like
enum item_type {
street,
town,
//lake,
border = town+2,
...
}
i.e. only explicitly assign a value to the item immediately following the one you remove.
Since compatibility is very important to you, it'd be more reliable to just bite the bullet and explicitly number all items
enum item_type {
street = 0,
town = 1,
//lake = 2,
border = 3,
...
}
I ended up declaring a macro UNUSED, which expands to
UNUSED_<linenumber>. Then unused enum values can just be replaced by
UNUSED. The macro expands to a unique identifier on each line it is
used because otherwise the compiler would complain about duplicate enum
entries it were used multiple times inside one enum.
This is slightly ugly if you have many "gaps". Still, I chose this
solution over simonc's solution because it easy to read (keeps the regular enum values free of visual
clutter like three=zero+2) and does not require magic numbers.
Admittedly this only makes sense if the gaps are few and far between.
For large gaps simonc's solution looks better.
Complete example:
#include <stdio.h>
#define UNUSED UNUSED_P(__LINE__)
#define UNUSED_P(x) UNUSED_P2(x)
#define UNUSED_P2(x) UNUSED_##x
enum e {
zero,
UNUSED,
UNUSED,
three,
};
int main(void){
printf("int value of 'three': %d\n",three);
return 0;
}
The double replacement is adapted from, among others, this question:
c++ - How, exactly, does the double-stringize trick work? .
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.
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.