Main Content

MISRA C:2023 Rule 10.1

Operands shall not be of an inappropriate essential type

Since R2024a

Description

Rule Definition

Operands shall not be of an inappropriate essential type.

Rationale

What Are Essential Types?

An essential type category defines the essential type of an object or expression.

Essential type categoryStandard types

Essentially Boolean

bool or _Bool (defined in stdbool.h)

You can also define types that are essentially Boolean using the option Effective boolean types (-boolean-types).

Essentially character

char

Essentially enum

named enum

Essentially signed

signed char, signed short, signed int, signed long, signed long long

Essentially unsigned

unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long

Essentially floating

real floating: float, double, long double

complex floating: float _Complex, doble _Complex, long double _Complex

Amplification and Rationale

For operands of some operators, you cannot use certain essential types. In the table below, each row represents an operator/operand combination. If the essential type column is not empty for that row, there is a MISRA restriction when using that type as the operand. The number in the table corresponds to the rationale list after the table.

OperationEssential type category of arithmetic operand
Operator Operand Boolean character enum signed unsigned floating
realcomplex
[ ] integer34   19
+ (unary) 345    
- (unary) 345 8  
+ - either3 5    
++ --  3 5   9
* / either345    
% either345  19
< > <= >= either3     9
== != either     1010
! && || any 222222
<< >> left345,66 19
<< >> right3477 19
~ & | ^ any345,66 19
?: 1st 222222
?: 2nd and 3rd       

  1. An expression of essentially floating type for these operands is a constraint violation.

  2. When an operand is interpreted as a Boolean value, use an expression of essentially Boolean type.

  3. When an operand is interpreted as a numeric value, do not use an operand of essentially Boolean type.

  4. When an operand is interpreted as a numeric value, do not use an operand of essentially character type. The numeric values of character data are implementation-defined.

  5. In an arithmetic operation, do not use an operand of essentially enum type. An enum object uses an implementation-defined integer type. An operation involving an enum object can therefore yield a result with an unexpected type.

  6. Perform only shift and bitwise operations on operands of essentially unsigned type. When you use shift and bitwise operations on essentially signed types, the resulting numeric value is undefined or implementation-defined.

  7. To avoid undefined behavior on negative shifts, use an essentially unsigned right-hand operand.

  8. For the unary minus operator, do not use an operand of essentially unsigned type. The implemented size of int determines the signedness of the result.

  9. An expression of essentially complex floating type for these operands is a constraint violation.

  10. Comparing floating-point types can result in unexpected and implementation-dependent results. When comparing floating-point types, take into account the floating point granularity (FLT_EPSILON) and the magnitudes of the numbers.

Note that for a bit-field type, if the bit-field is implemented as:

  • A Boolean, the bit-field is essentially Boolean.

  • Signed or unsigned type, the bit-field is essentially signed or unsigned respectively.

    The type of the bit-field is the smallest type that can represent the bit-field. For instance, the type stmp here is essentially 8 bits integer:

    typedef signed int mybitfield;
    typedef struct { mybitfield f1 : 1; } stmp;

Polyspace Implementation

Polyspace® reports violation of this rule when the operand of an operation is of inappropriate essential types. As exceptions, Polyspace does not report violation on these use cases:

  • Using a non-negative integer constant expression of essentially signed type as the right operand of a shift operator.

  • Comparing essentially real floating or essentially complex floating object with the constant literal zero or the macro INFINITY or -INFINITY.

Troubleshooting

If you expect a rule violation but do not see it, refer to Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

#include<stdbool.h>
extern float f32a;
extern char cha; 
extern signed char s8a;
extern unsigned char u8a,u8b,ru8a;
enum enuma { a1, a2, a3 } ena, enb; 	
extern bool bla, blb, rbla; 
void foo(void) {

	rbla = cha && bla;        /* Non-compliant: cha is essentially char  */
	enb = ena ? a1 : a2;      /* Non-compliant: ena is essentially enum  */
	rbla = s8a && bla;        /* Non-compliant: s8a is essentially signed char  */
	ena = u8a ? a1 : a2;      /* Non-compliant: u8a is essentially unsigned char  */
	rbla = f32a && bla;       /* Non-compliant: f32a is essentially float */
	rbla = bla && blb;        /* Compliant */
	ru8a = bla ? u8a : u8b;   /* Compliant */
}

In the noncompliant examples, rule 10.1 is violated because:

  • The operator && expects only essentially Boolean operands. However, at least one of the operands used has a different type.

  • The first operand of ?: is expected to be essentially Boolean. However, a different operand type is used.

Note

For Polyspace to detect the rule violation, you must define the type name boolean as an effective Boolean type. For more information, see Effective boolean types (-boolean-types).

#include<stdbool.h>
enum enuma { a1, a2, a3 } ena; 
enum { K1 = 1, K2 = 2 };    /* Essentially signed */
extern char cha, chb; 
extern bool bla, blb, rbla; 
extern signed char rs8a, s8a;
extern unsigned char u8a;

void foo(void) {

  rbla = bla * blb;      /* Non-compliant - Boolean used as a numeric value */
  rbla = bla > blb;      /* Non-compliant - Boolean used as a numeric value */

  rbla = bla && blb;     /* Compliant */
  rbla = cha > chb;      /* Compliant */
  rbla = ena > a1;       /* Compliant */ 
  rbla = u8a > 0U;       /* Compliant */
  rs8a = K1 * s8a;       /* Compliant - K1 obtained from anonymous enum */

}

In the noncompliant examples, rule 10.1 is violated because the operators * and > do not expect essentially Boolean operands. However, the operands used here are essentially Boolean.

Note

For Polyspace to detect the rule violation, you must define the type name boolean as an effective Boolean type. For more information, see Effective boolean types (-boolean-types).

extern char rcha, cha, chb; 
extern unsigned char ru8a, u8a;

void foo(void) {

  rcha = cha & chb;      /* Non-compliant - char type used as a numeric value */
  rcha = cha << 1;       /* Non-compliant - char type used as a numeric value */

  ru8a = u8a & 2U;       /* Compliant */	
  ru8a = u8a << 2U;      /* Compliant */
 
}

In the noncompliant examples, rule 10.1 is violated because the operators & and << do not expect essentially character operands. However, at least one of the operands used here has essentially character type.

typedef unsigned char boolean;

enum enuma { a1, a2, a3 } rena, ena, enb; 

void foo(void) {

  ena--;             /* Non-Compliant - arithmetic operation with enum type*/
  rena = ena * a1;   /* Non-Compliant - arithmetic operation with enum type*/
  ena += a1;         /* Non-Compliant - arithmetic operation with enum type*/

}

In the noncompliant examples, rule 10.1 is violated because the arithmetic operators --, * and += do not expect essentially enum operands. However, at least one of the operands used here has essentially enum type.

extern signed char s8a;
extern unsigned char ru8a, u8a;

void foo(void) {

  ru8a = s8a & 2;       /* Non-compliant - bitwise operation on signed type */
  ru8a = 2 << 3U;       /* Non-compliant - shift operation on signed type */
	
  ru8a = u8a << 2U;     /* Compliant */	

}

In the noncompliant examples, rule 10.1 is violated because the & and << operations must not be performed on essentially signed operands. However, the operands used here are signed.

extern signed char s8a;
extern unsigned char ru8a, u8a;

void foo(void) {

  ru8a = u8a << s8a;    /* Non-compliant - shift magnitude uses signed type */	
  ru8a = u8a << -1;     /* Non-compliant - shift magnitude uses signed type */	

  ru8a = u8a << 2U;     /* Compliant */	
  ru8a = u8a << 1;      /* Compliant - exception */	

}

In the noncompliant examples, rule 10.1 is violated because the operation << does not expect an essentially signed right operand. However, the right operands used here are signed.

#include <complex.h>
#include <stdbool.h>
#include <math.h>
_Complex float cnx, cny;
float fx;
void amd3() {

      cnx ? 1 : 0;                    // Noncompliant
      cny = !cnx;                     // Noncompliant
      cny = cnx && cny;               // Noncompliant
      cny = cnx || cny;               // Noncompliant
      if(fx!=0.0f) // Compliant
      {}
      if(cnx!= INFINITY) // Compliant
      {}
}

In the examples, Polyspace reports violations of rule 10.1 because essentially floating type operands are used with the operators == and !=. As exceptions, using these operators to compare essentially floating type operands to 0.0f and INFINITY is not a violation.

Check Information

Group: The Essential Type Model
Category: Required
AGC Category: Advisory

Version History

Introduced in R2024a