Avoid name collisions with enum in C (C99)
Asked Answered
T

2

12

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.

Thalia answered 13/2, 2016 at 13:8 Comment(10)
Yes, use an appropriate name like color_orange and fruit_orange. It should also avoid the confusion when reading.Crawler
Is there a [...] solution other than prefixing every enum element name ?Thalia
Maybe but it would likely be a bad solution, this is a good solution that helps readability too.Crawler
is there anything better readable than Fruit f = orange; and Color c = orange; ? It's tidy and no doubt than f is a fruit and c a colorThalia
Yes Fruit fruit = FruitOrange;. Oh and in this case switch (fruit) {case FruitOrange: break ...}. If there are many fruits you will be glad to prefix them. Also f can be for file, f**ck, and many other wrods that start with f fruit instead is simply fruit.Crawler
that's ugly! :-) but of course if it's the only solution I'll go with that. "There is no solution for that" (if true) may be an appropriate answer.Thalia
It's not ugly Fuirt f = orange; is ugly, why not make it Fruit f = o; too and shorten it more to make it prettier?Crawler
I don't understand the question entirely. Do you want to refer to different entities with the same name?Karb
@IharobAlAsimi, f is a letter. Why do you assume f must always stand for a word? Sometimes verbosity is pointless within context, more difficult to read, and leads to typos as you already mixed up "Fuirt" with "Fruit." When you start down the path of "do this thing because I was told it is good," you often end up in a mire, as is evidenced by the appalling state of software "development" we see these days; where all the code runs slower, is harder to read, harder to maintain, and with more bugs every year. A million 4-line, verbose functions in a half-million 2-function files. Yuck!Stairhead
Not an answer, but an alternative ... <<const struct { const int apple, pear, orange; } Fruit = { 0,1,2 };>> .... then reference 'Fruit.orange' . Enums seem pretty awfulMix
P
11

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.

Pasta answered 13/2, 2016 at 14:20 Comment(3)
Would just like to add a link to an answer that complements this one: https://mcmap.net/q/968475/-c-using-enum-inside-structRaffia
Some claim that Namespace::variableName or Namespace.variable_name is "prettier" or "better," without specifying a metric with which to make these subjective judgements. A simple Namespace_variable does the same thing, with less typing. NamespaceVariable also. It's mainly personal preference unless extra type info can be utilized with an enum class or equivalent, if the language supports it.Stairhead
In C++20 at least you are not forced to always use the enum-name for scoped enums - usingallows you to bring the enum directly into scope. Example: using enum Fruit; Fruit f = orange;Ault
L
1

Although this is not actually an enum, it functions similarly enough to one to be useful in some contexts. Note that because these are runtime constants, not compile-time constants, they aren't valid inside switch statements. If constexpr (C23) is ever expanded to allow non-scalar types, then it would be possible to make these compile-time constants (but that is just wishful thinking).

// `Fruit` pseudo-enum

typedef int Fruit;
static const struct
{
    Fruit apple;
    Fruit orange;
} _Fruit = { 0, 1 };

// `Color` pseudo-enum

typedef int Color;
static const struct
{
    Color red;
    Color orange; // No error
} _Color = { 0, 1 };

// Using them...

int main()
{
    Fruit foo = _Fruit.apple;
    Color bar = _Color.orange;
    
    char apple = 'a'; //  No error

    return 0;
}
Lothaire answered 26/4 at 23:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.