2

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?

Community
  • 1
  • 1
m4l490n
  • 1,592
  • 2
  • 25
  • 46
  • this shouldn't apply to standard C defined by ISO. it should be specific in specified standard.. – Jason Hu Aug 10 '15 at 20:04
  • Look up the MISRA definition of "essential type". It's different from the actual type of the expression in C. – R.. GitHub STOP HELPING ICE Aug 10 '15 at 20:07
  • Just an observation: debuggers (at least a few that I've used) have the same problem with named and unnamed structures. It seems that internally the *type* of the object is determined by the structure tag or enum tag, and the typedef is merely an alias used by the compiler, but not by the debugger or the rules checker. – user3386109 Aug 10 '15 at 20:08
  • @user3386109: How could I know for sure if this is the case? – m4l490n Aug 10 '15 at 20:35

4 Answers4

3

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.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
3

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:

  1. an object of an enum type intended to be distinct from an object with a different enum type.
  2. 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):

  1. 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.
  2. 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.

Veriloud
  • 417
  • 3
  • 9
1

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.

Lundin
  • 195,001
  • 40
  • 254
  • 396
-1

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;

}
user3629249
  • 16,402
  • 1
  • 16
  • 17
  • 2
    Can you explain why not to typedef it? And does it apply to `struct`s? – Eugene Sh. Aug 10 '15 at 20:09
  • 2
    could you elaborate? why it's bad? what about typedef a struct, a union, or a primitive? – Jason Hu Aug 10 '15 at 20:09
  • Well that's good, but here in the company one of the coding rules is that all structs and enums are declared as typedefs and then create variables out of those typedefs to use them. – m4l490n Aug 10 '15 at 20:10
  • 1
    @HuStmpHrrr: I agree, but with a team of many people, both experienced and not so much, it helps to keep people from doing weird things, makes the code look somewhat "standarized", and helps avoiding some errors. And that's good at some degree – m4l490n Aug 10 '15 at 20:20
  • I'm not going to down-vote (just yet) but I'd be interested to know your reasoning... happy to Chat about about it (http://chat.stackoverflow.com/rooms/85390/misra-musings) – Andrew Aug 11 '15 at 05:46