J'ai reçu un avertissement MISRA-C de la règle 10.8: Une expression composite de type «essentiellement non signé» (caractères non signés) est en cours de conversion en un type non signé plus large, «short unsigned».

Cet avertissement a été détecté avec le code suivant.

void Fucntion(unsigned char isSwitchOn) {
    unsigned short switchMask = 0U;

    switchMask |= (unsigned short)(isSwitchOn & 1U) << 1;

Pourquoi un avertissement a-t-il été détecté? En outre, ce code pose-t-il des problèmes?

Je pense que l'expression (isSwitchOn & 1U) est convertie en un type int et calculée, et le résultat est tronqué et stocké en tant que type court non signé. En pensant ainsi, l'avertissement ne me paraît pas naturel.

2
Khen 26 nov. 2017 à 01:38

3 réponses

Meilleure réponse

Pourquoi un avertissement a-t-il été détecté?

Regardons

void Fucntion(unsigned char isSwitchOn) {
  unsigned short switchMask = 0U;
  switchMask |= (unsigned short)(isSwitchOn & 1U) << 1;
  1. isSwitchOn, étant de rang inférieur à 1U, passe par la conversion arithmétique habituelle (C11 §6.5.10 3) au type unsigned pour correspondre au type de 1U.

  2. isSwitchOn & 1U est calculé, le type de résultat est unsigned.

  3. Cast (unsigned short) est appliqué au résultat unsigned - cette étape semble étrange. Ceci est l'avertissement MISRA-C de la règle 10.8. Il n'y a pas besoin du casting. Le type composite unsigned est inutilement réduit à unsigned short.

  4. Le résultat (unsigned short) est préparé pour le décalage et des promotions d'entiers sont effectuées sur chacun des opérandes du <<. Donc le (unsigned short) est promu int ou éventuellement unsigned si USHRT_MAX > INT_MAX. Supposons int.

  5. Maintenant, le décalage d'un int se produit. Le résultat est le type int.

  6. Le int est appliqué à un unsigned short.


En outre, ce code pose-t-il des problèmes?

Je ne vois pas dans ce cas , la distribution causant un problème autre que celui-ci est programmation WET. Si le résultat avait été unsigned switchMask, oui alors le bit décalé aurait été perdu.

Il est plus logique de lancer le résultat après le quart de travail. @Myst

switchMask |= (unsigned short)((isSwitchOn & 1U) << 1);

Ou évitez d'autres avertissements potentiels avec

switchMask = (unsigned short)(switchMask | ((isSwitchOn & 1U) << 1));

Je pense que l'expression (isSwitchOn & 1U) est convertie en un type int et calculée

Non, l'expression (unsigned short)(isSwitchOn & 1U) est convertie en un type int et calculée.


Remarque: il est douteux que unsigned char isSwitchOn et unsigned short switchMask ne soient pas du même type.

1
chux - Reinstate Monica 25 nov. 2017 à 23:41

Chux a publié une réponse qui explique ce qui se passe avec le code et pourquoi il est faux. Quant à savoir comment le réparer, vous devez le réécrire. Il y a deux problèmes:

  • Vous utilisez un type de caractère comme booléen, puis vous utilisez également ce type de caractère en arithmétique, en convertissant le type après les promotions, au lieu de les précéder. On suppose que cela est fait pour se débarrasser des branches supplémentaires.
  • Vous utilisez les types entiers natifs de C, qui peuvent avoir n'importe quelle taille. Cette pratique n'est pas recommandée et enfreint MISRA-C: 2012 Dir 4.6. Débarrassez-vous de ces types et utilisez stdint.h à la place, ce qui vous permet d'écrire du code déterministe et portable.

Maintenant, il y a deux façons de gérer les promotions de type implicites: soit vous les laissez se produire et vous les lancez ensuite - c'est généralement ce que MISRA préfère. Ou vous ne les laissez pas du tout se produire, en convertissant en un type large non signé avant que l'opération ne soit évaluée, éliminant ainsi la promotion implicite. L'un ou l'autre devrait être bien en ce qui concerne MISRA; Je préfère personnellement ce dernier.

Le code fixe ressemblerait à ceci:

// ok if 8/16 bit system only
void Function (bool isSwitchOn) {
    uint16_t switchMask = ((uint16_t)isSwitchOn & 1U) << 1U;

Ou

// 32 bit system/fully portable code
void Function (bool isSwitchOn) {
    uint32_t shift = (uint32_t)isSwitchOn & 1U;
    uint16_t switchMask = (uint16_t) (shift << 1U);

Veuillez noter que ces exemples doivent générer le même code machine. Vous pouvez donc également utiliser la version entièrement portable sur un système 8 bits. Les deux sont conformes MISRA-C sur les systèmes donnés - aucune promotion implicite n'a lieu nulle part.

Plus d'informations: Règles de promotion de type implicite.

0
Lundin 27 nov. 2017 à 10:08

En ce qui concerne:

unsigned short switchMask = 0U;

Cette instruction attribue un unsigned short int à l'aide d'un unsigned int

En ce qui concerne:

switchMask |= (unsigned short)(isSwitchOn & 1U) << 1;

Cette instruction est anding un unsigned short int avec un unsigned int

0
user3629249 25 nov. 2017 à 22:53
47491192