Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Essential type of ~(uint16_t)0x30
#1
What is the essential type of "~(uint16_t)0x30" ?

Going by Appendix D "Bitwise complement":
* The operand is essentially unsigned
* The operand is an integer constant expression
* The result of "~(uint16_t)0x30" is -49 of standard type int (assuming int is 32 bits and twos complement).
* The UTLR of -49 is ill-defined.

Option 1: If the resulting constant is negative, convert it to the unsigned type corresponding to the expression's standard type, then use the UTLR of that converted value. This would result in "~(uint16_t)0x30" having essential type "unsigned int" (same as without the cast to uint16_t).

Option 2: If the resulting constant is negative, treat the expression as if it was non-constant, using the essential type of the operand instead. This would result in "~(uint16_t)0x30" having essential type "uint16_t" (same as if 0x30 wasn't a compile-time constant).

Option 3: If the resulting constant is negative, use the standard type for the essential type. This would result in "~(uint16_t)0x30" having essential type "signed int".

This also affects other constant expressions producing negative values after integral promotion, e.g. "(uint16_t)300u - (uint16_t)301u".
<t></t>
#2
This discussion assumes that "uint16_t" is a 16-bit unsigned short, and that "uint32_t" is a 32-bit unsigned int.

Taking the operators in turn.
(uint16_t)0x30 The result of the cast has an essential type of unsigned short and a value of 0x30

Appendix D on the ~ operator says:
Quote:1. If the operand is essentially unsigned then:
1.1 If the operand is an integer constant expression then the essential type
of the result is the UTLR of the result;
1.2 Else the essential type of the result is the essential type of the operand.
2. Else the essential type is the standard type.

The operand is essentially unsigned and the operand is an integer constant expression, so option 1.1 is selected.
Therefore the result is of the ~ operator has an essential type which is unsigned. The value of the result occupies 32-bits and so the essential type of the result is unsigned int.

You are correct in saying that small unsigned types are promoted to a "signed int" standard type, but have an "essentially unsigned" type. This is only an issue if the resultant value is treated as a signed value, otherwise the bit pattern is consistent with what a user would expect. Any attempt to use the value of the result in an essentially signed context will produce a violation of rule 10.1, 10.3 or 10.4.
Code:
uint16_t u16 = ~(uint16_t)0x30;  // Rule 10.3 violation  - uint16_t v uint32_t
  uint32_t u32 = ~(uint16_t)0x30;  // Compliant
   int32_t s32 = ~(uint16_t)0x30;  // Rule 10.3 violation  - sint32_t v uint32_t
Any use which might indicate a loss of bits is highlighted by a MISRA C:2012 warning.

The same argument follows for (uint16_t)300U - (uint16_t)301U. Appendix D on "-" paragraph 2.1 says
Quote:"If the expression is an integer constant expression then the essential type of the result is the UTLR of the result;"
The result would have a value of -1 in the standard C operation which requires 32-bits and hence the UTLR is "unsigned int".
Posted by and on behalf of the MISRA C Working Group


Forum Jump:


Users browsing this thread: 1 Guest(s)