Question

Compte tenu de l'extrait suivant:

#include <stdio.h>

typedef signed long long int64;
typedef signed int int32;
typedef signed char int8;

int main()
{
    printf("%i\n", sizeof(int8));
    printf("%i\n", sizeof(int32));
    printf("%i\n", sizeof(int64));

    int8 a = 100;
    int8 b = 100;
    int32 c = a * b;
    printf("%i\n", c);

    int32 d = 1000000000;
    int32 e = 1000000000;
    int64 f = d * e;
    printf("%I64d\n", f);
}

La sortie avec MinGW GCC 3.4.5 est (-O0):

1
4
8
10000
-1486618624

La première multiplication est coulé à une int32 interne (en fonction de la sortie de l'assembleur). La deuxième multiplication n'est pas casté. Je ne sais pas si les résultats diffèrent parce que le programme était en cours d'exécution sur un IA32, ou parce qu'il est défini quelque part dans la norme C. Néanmoins, je suis intéressé si ce comportement exact est défini quelque part (ISO / CEI 9899?), Parce que je aime mieux comprendre pourquoi et quand je l'ai à la main casting (j'ai des problèmes à porter un programme à partir d'une architecture différente).

Était-ce utile?

La solution

La norme C99 ne précise que les opérateurs binaires tels que * ne pas fonctionner sur les types entiers plus petits que int. Les expressions de ces types sont promus à int avant l'application de l'opérateur. Voir 6.3.1.4 paragraphe 2 et les nombreuses occurrences des mots « entiers promotion ». Mais cela est un peu orthogonale aux instructions de montage générées par le compilateur, qui fonctionnent sur ints parce que c'est plus rapide même lorsque le compilateur serait autorisé à calculer un résultat plus court (car le résultat est immédiatement stocké dans une l valeur d'un type court , par exemple).

En ce qui concerne int64 f = d * e;d et e sont de type int, la multiplication se fait comme int selon les mêmes règles de promotion. Le trop-plein est techniquement comportement undefined , vous obtenez résultat deux s-complément, mais vous pourriez obtenir quoi que ce soit selon la norme.

Note: les règles de promotion de types signés et peuvent distinguer non signés lors de la promotion. La règle est de promouvoir les petits types de int à moins int ne peut pas représenter toutes les valeurs du type, auquel cas unsigned int est utilisé.

Autres conseils

Le problème est que la multiplication est int32 * int32, qui se fait comme int32, et le résultat alors affecté à un int64. Vous obtiendrez le même effet avec double d = 3 / 2;, qui diviserait 3 par 2 en utilisant la division entière, et assign 1,0 à d.

Vous devez faire attention au type d'une expression ou une sous-expression chaque fois qu'il peut jouer. Cela nécessite en vous assurant que l'opération appropriée est calculée comme le type approprié, comme le moulage l'un des multiplicandes à int64, ou (dans mon exemple) 3.0 / 2 ou (float)3 / 2.

Lire K & R (l'original). Toutes les opérations entières sont effectuées avec le type entier naturel à moins qu'il implique des variables qui sont (ou sont Casted) à quelque chose de plus grand. Les opérations sur l'omble sont casté en 32 bits parce que c'est la taille naturelle du nombre entier sur cette architecture. La multiplication des deux entiers 32 bits se fait en 32 bits parce que rien ne jette à quoi que ce soit plus grand (jusqu'à ce que vous attribuez à la variable 64 bits, mais c'est trop tard). Si vous souhaitez que l'opération se produise en 64 bits, jeté un ou deux ints à 64 bits.

int64 f = (int64)d * e;

a * b est calculée comme un int, et ensuite coulé dans le type de variable de réception (qui se trouve être int)

d * e est calculée comme un int, et ensuite coulé dans le type de variable de réception (qui se trouve être int64)

Si l'une des variables de type étaient plus grandes qu'un int (ou étaient en virgule flottante), que ce type aurait été utilisé. Mais puisque tous les types utilisés dans les multiplications étaient int ou moins, ints ont été utilisés.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top