2011-09-26 3 views
5

Nous avons trouvé des valeurs étranges en cours de production, un petit cas de test est ci-dessous. Ceci imprime "FFFFFFFFF9A64C2A". Ce qui signifie que le long signe non signé semble avoir été prolongé. Mais pourquoi? Tous les types ci-dessous ne sont pas signés, alors que fait l'extension de signe? La sortie attendue serait "F9A64C2A".Extension de signe avec unsigned long long

#include <stdio.h> 

int main(int argc,char *argv[]) 
{ 
    unsigned char a[] = {42,76,166,249}; 

    unsigned long long ts; 
    ts = a[0] | a[1] << 8U | a[2] << 16U | a[3] << 24U; 

    printf("%llX\n",ts); 


    return 0; 

} 

Répondre

5

Dans l'expression a[3] << 24U, le a[1] est de type unsigned char. Maintenant, la "promotion entière" convertit en int parce que:

Les éléments suivants peuvent être utilisés dans une expression où un int ou unsigned int peut être utilisé :

[...]

Si int peut représenter toutes les valeurs du type d'origine, la valeur est convertie en et int; sinon, il est converti en unsigned int.

((draft) ISO/IEC 9899:1999, 6.3.1.1 2)

S'il vous plaît noter également que les opérateurs de décalage (autres que la plupart des autres opérateurs) ne pas faire les « conversions arithmétiques habituelles » convertir les deux opérandes à un type commun . Mais

Le type du résultat est celui de l'opérande gauche promu.

(6.5.7 3)

Sur une plate-forme 32 bits, 249 << 24 = 4177526784 interprétée comme une int a son bit de signe.

Juste pour changer

ts = a[0] | a[1] << 8 | a[2] << 16 | (unsigned)a[3] << 24; 

résout le problème (le suffixe U pour les constantes n'a pas d'impact).

+0

Correction mineure: 'a [1]' a le type 'unsigned char'. –

+0

@ user964970: relire. Le type de 'x << y' n'a rien à voir avec le type de' y'. –

+0

@Dietrich Epp: Merci. –

1
 
ts = ((unsigned long long)a[0]) | 
    ((unsigned long long)a[1] << 8U) | 
    ((unsigned long long)a[2] << 16U) | 
    ((unsigned long long)a[3] << 24U); 

coulée empêche la conversion des résultats intermédiaires de type à défaut d'int.

+1

Mais * pourquoi * existe-t-il un résultat int intermédiaire, lorsque tous les types impliqués sont des types non signés? Le coupable semble être seulement le premier 'a [0]', en remplaçant cela par '(unsigned) a [0]' tout va bien. Mais pourquoi. – user964970

1

Certains des éléments a [i] décalés, convertis automatiquement de unsigned char à int, produisent des valeurs étendues de signe.

Ceci est en accord avec le paragraphe 6.3.1 Opérandes arithmétiques, sous-section 6.3.1.1 Booléen, caractères et entiers, du projet de norme N1570, qui lit, en partie, "2. Ce qui suit peut être utilisé dans une expression partout où un entier int ou unsigned peut être utilisé: ... - Un objet ou une expression avec un type entier (autre que int ou unsigned int) dont le rang de conversion entier est inférieur ou égal au rang de int et unsigned int. .. Si un int peut représenter toutes les valeurs du type d'origine ..., la valeur est convertie en int, sinon, il est converti en un entier non signé Ce sont les promotions entières ... 3. Les promotions entières préserver la valeur y compris le signe. "

Voir par exemple www.open-std.org/JTC1/SC22/WG14/www/docs/n1570.pdf

Vous pouvez utiliser le code comme suit, qui fonctionne bien:

 int i; 
     for (i=3, ts=0; i>=0; --i) ts = (ts<<8) | a[i]; 
+0

Tous les [i] qui sont décalés, dans l'exemple de code, ont le côté droit non signé en raison du préfixe U sur la constante. (par exemple << 8U), signifiant par ex. l'expression a [1] << 8U devrait déjà avoir un type non signé, selon ces règles. – user964970

+0

@ user964970: Le coupable n'est pas 'a [0]'. Cependant, lancer 'a [0]' à unsigned' force le résultat du bitwise ou être 'unsigned', ce qui tronque l'extension de signe qui apparaît dans' a [3] << 24', qui est le vrai coupable. –

Questions connexes