essential type of constant expression

Moderators: misra-c, david ward

Post Reply
sowiso
Posts: 2
Joined: Thu Jun 01, 2017 12:47 pm
Company: ...

essential type of constant expression

Post by sowiso » Tue Sep 26, 2017 1:01 pm

In Appendix D.1 the following limitation for the paragraphs D.n:
The essential type of an expression only differs from the standard C type (standard type) in expressions where the standard type is either signed or unsigned int.
What exactly is meant by expression?
For example if I have the following code:

Code: Select all

uint_8 foo = (((uint_8)(900000Lu / 5000Lu)) - ((uint_8)(600000Lu / 5000Lu))) - 1u; 
Is the complete part "(((uint_8)(900000Lu / 5000Lu)) - ((uint_8)(600000Lu / 5000Lu))) - 1u" to be treated as exact one expression or does it have to be split up into separate expressions step by step until it comes down to a + b to decide if the limitations from D.1 applies and paragraph D.7 takes effect.

In case I take the complete part from above as one single expression, for the code example the standard type of the complete expression would be evaluated to "(unsigned char - unsigned char) - unsigned int" which is promoted to "(signed int - signed int) - unsigned int" evaluated to "signed int - unsigned int" converted to "unsigned int - unsigned int" and finally results in "unsigned int".
Based on this result, which is unsigned int, the rules from D.7 needs to be applied.

However looking at the final expression "signed int - unsigned int" D.7 tells the following:
1. If the operands are both essentially signed then
[...]
2. Else if the operands are both essentially unsigned then
[...]
3. Else the essential types are the standard type
Since one is essentially signed while the other is essentially unsigned the result is the standard type which is unsigned int.

The numerical value value in this case would be 59u which would have the UTLR as unsigned char.
But since case 3 applies the final type is still unsigned int and therefore an assignment to uint_8 type variable is prohibited because of Rule 10.3 "The value of an expression shall not be assigned to an object with a narrower essential type [...]".


Looking at this on a different way and evaluate each sub expression separately by use of the essential type model I come to a different result.

(((uint_8)(900000Lu / 5000Lu)) - ((uint_8)(600000Lu / 5000Lu))) -1u;

(900000Lu / 5000Lu): both types are unsigned long int and therefore also the result will be unsigned long int. D.7 does not apply because of D.1.
=> 180Lu
result of the cast to ((uint_8)(180Lu)) is the standard type as casts are not specified in D.7 giving the result at unsigned char 180u.
For (600000Lu / 5000Lu) it is the same result as unsigned long, cast afterwards to unsigned char 120u.
The next expression is then "unsigned char 180u - unsigned char 120u". The result of this is signed int and therefore D.7 applies.
"2. Else if the operands are both essentially unsigned"
"2.1 If the expression is an integer constant expression the essential type of the result is the UTLR of the result."
This gives the result as 60u which has the UTLR of unsigned char.
Now "unsinged char 60u - unsigned int 1u" will be promoted to "signed int - unsigned int" and converted to "unsinged int - unsigned int" returning an unsigned int. Therefore D.7 applies and the result will be 59u which has the UTLR of unsigned char.
Based on this an assignment to uint_8 type variable is allowed.

Now my question is, which of these two approaches is the right one?

misra-c
Posts: 566
Joined: Thu Jan 05, 2006 1:11 pm

Re: essential type of constant expression

Post by misra-c » Tue Jan 30, 2018 9:33 am

Code: Select all

uint_8 foo = (((uint_8)(900000Lu / 5000Lu)) - ((uint_8)(600000Lu / 5000Lu))) - 1u;
This can be best explained by working up the tree of operations. It is assumed that all values of the "unsigned char" type fit in the "signed int" type.

1. 900000Lu ( and other Lu literals)
The literal has a C standard type of "unsigned long", which has a rank greater than the rank of "int". Therefore the essential type is the same as the standard type which is "unsigned long".

2. 900000Lu / 5000Lu
The "/" operation is between 2 literals with a C type and ET of "unsigned long".
The resultant C type is "unsigned long", which has a rank greater than the rank of "int". Therefore the essential type is the same as the standard type which is "unsigned long".

3. (uint_8)(900000Lu / 5000Lu)
This casts a C "unsigned long" type to "unsigned char".
Casts are not listed in Appendix D.7 and so the essential type will be that of the cast. i.e "unsigned char".

4. (uint_8)(600000Lu / 5000Lu)
For the same reasons as 1 - 3 the essential type is "unsigned char"

5. (((uint_8)(900000Lu / 5000Lu)) - ((uint_8)(600000Lu / 5000Lu)))
The "-" operation is between two C types of "unsigned char".
C's unary promotion rule promotes each operand to "signed int" and therefore the C resultant type of the expression is "signed int".
As the C type of the expression is "signed int", the essential type is determined by the value of the expression.
The value of the expression is 60 and hence the UTLR and essential type is "unsigned char".

6. 1u
The literal has a C type of "unsigned int" and an essential type of "unsigned char".

7. (((uint_8)(900000Lu / 5000Lu)) - ((uint_8)(600000Lu / 5000Lu))) - 1u
The "-" operation is between the C types of "signed int" and "unsigned int", and the essential types of "unsigned char" and "unsigned char".
C's promotion rules converts the LH operand to "unsigned int", so the C resultant type of the expression is "unsigned int".
As the C type of the expression is "unsigned int", the essential type is determined by the value of the expression.
The value of the expression is 59 and hence the UTLR and essential type is "unsigned char".
---
Posted by and on behalf of
the MISRA C Working Group

Post Reply

Return to “8.10 The essential type model”