10.1: Can the underlying type of enum constants be unsigned? - Printable Version +- MISRA Discussion Forums (https://forum.misra.org.uk) +-- Forum: MISRA C (https://forum.misra.org.uk/forumdisplay.php?fid=4) +--- Forum: MISRA-C: 2004 rules (https://forum.misra.org.uk/forumdisplay.php?fid=17) +---- Forum: 6.10 Arithmetic Type Conversions (https://forum.misra.org.uk/forumdisplay.php?fid=37) +---- Thread: 10.1: Can the underlying type of enum constants be unsigned? (/showthread.php?tid=788) |
10.1: Can the underlying type of enum constants be unsigned? - andersl - 09-11-2010 After reading the MISRA-C:2004 guideline and earlier posts to this forum, I have concluded the following about enum:s: * An enum object is in standard C "int", and hence has the underlying type "int". * An enum constant has the underlying type corresponding to the magnitude, as specified by the table in 6.10.4 However, this leaves one open question: What is the sign of an enum constant? The background is that in embedded devices, peripheral units are often memory mapped and described using a struct, for example: Code: /* Typical peripheral usage */ initializer expression. In other words, can enum constants be unsigned? Alternative 1: Always signed If we assume that the underlying type is signed, then the assignment in "test1" will break rule 10.1, as the expression to the right has the underlying type "signed char". If this is the case, enum can't be used to describe bits in bitmask in a MISRA-C-compliant application. This is a big drawback and would make MISRA-C much less useful in real-world applications, as it would force peripheral units to be described using preprocessor macros. Alternative 2: Get type from the initializer expression On the other hand, if the enum constants inherit the underlying type from the initializer expression, it could be something like "unsigned char". In which case, any operation involving an enum object (int) and enum constants (e.g. unsigned char) appears to break rule 10.1, as there will be an implicit conversion from "unsigned char" to "signed int". For example, see the comparison in "test2". Also, if this enum constant inherit the signedness from initializer expression, what happens when the expression is left out, should it inherit the type from the previous enum constant? Code: enum my_other_enum To conclude, I would like to know if enum constants should inherit the signedness from the initializer expressions and, if so, should the tools issue a MISRA-C error for expressions involving enum objects and enum constants? By the way, I work for a company providing a MISRA-C checker. In order to make the tools as good as possible, I would like to get a straight answer to the questions I ask in relation to rule 10.1 -- whether or not the example code breaks other MISRA-C rules is irrelevant. Re: 10.1: Can the underlying type of enum constants be unsig - misra-c - 19-11-2010 The C Standard says (C90, Section 6.5.2.2) that each enumerated type is compatible with an integer type but the choice of integer type is implementation-defined. Many implementations, including those for some popular embedded processors, choose the smallest type that can contain the range of values of the enumeration constants. This type may be signed or unsigned. So, an enum object may be an int but it may be some other integer type. The C Standard also says (C90, Sections 6.1.3.3 and 6.5.2.2) that the enumeration constants have type int, regardless of the integer type that is used to represent their parent enumerated type. Section 6.5.2.2 also constrains enumeration constants to have a value that is representable as an int. The underlying type of an enumeration constant is determined from the table in MISRA C:2004 Guidelines Section 6.10.4. But, note that the Guidelines say, also in Section 6.10.4, that if the actual type of the expression is (signed) int ,then the underlying type is the smallest signed integer type capable of representing the value. Since all enumeration constants have type int, the underlying type of all enumeration constants is signed. The code example: Code: s.x = (FIELD1 | FIELD2); violates Rule 10.1 because the right operand of = has underlying type signed char and this is implicitly converted to an unsigned 16-bit type. A type cast will be needed to avoid this violation. However, the code also violates Rule 12.7 because the bitwise OR operator is applied to operands with a signed underlying type. A better solution might therefore be to cast the enumeration constants to an unsigned type, e.g. Code: s.x = ((my_uint16_t)FIELD1 | (my_uint16_t)FIELD2); It might be worth using macros to perform the casts and thereby provide unsigned versions of the enumeration constants, e.g. Code: #define FIELD1_U ((my_uint16_t)(FIELD1)) To recap the answers to the concluding questions: Quote:To conclude, I would like to know if enum constants should inherit the signedness from the initializer expressions No, enum constants are always signed. Quote:and, if so, should the tools issue a MISRA-C error for expressions involving enum objects and enum constants? That would depend on the nature of the expressions but code such as: Code: enum { A, B } e; will not violate any arithmetic type rules. |