MISRA C:2012 Rule 10.1

Operands shall not be of an inappropriate essential type

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 -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

float, double, long double

For more information on analysis options, see the documentation for Polyspace® Code Prover™ or Polyspace Code Prover Server™.

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
OperatorOperandBooleancharacterenumsignedunsignedfloating
[ ]integer34   1
+ (unary) 345   
- (unary) 345 8 
+ -either3 5   
* /either345   
%either345  1
< > <= >=either3     
== !=either      
! && ||any 22222
<< >>left345,66 1
<< >>right3477 1
~ & | ^any345,66 1
?:1st 22222
?: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 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.

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;

Additional Message in Report

The operand_name operand of the operator_name operator is of an inappropriate essential type category category_name.

Troubleshooting

If you expect a rule violation but do not see it, refer to the documentation of Polyspace Code Prover or Polyspace Code Prover Server.

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). For more information on analysis options, see the documentation for Polyspace Code Prover or Polyspace Code Prover Server.

#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). For more information on analysis options, see the documentation for Polyspace Code Prover or Polyspace Code Prover Server.

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.

Check Information

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