Question

Pourquoi est-ce que je reçois quand je -1 imprimer ce qui suit?

unsigned long long int largestIntegerInC = 18446744073709551615LL;

printf ("largestIntegerInC = %d\n", largestIntegerInC);

Je sais que je devrais utiliser llu au lieu de d, mais pourquoi dois-je obtenir -1 au lieu de 18446744073709551615LL?

est-ce à cause de trop-plein?

Était-ce utile?

La solution

C (99), LLONG_MAX, la valeur maximale du type de long long int est garanti pour être au moins 9223372036854775807. La valeur maximale d'un unsigned long long int est assuré d'être au moins 18446744073709551615, qui est 2 64 -1 (0xffffffffffffffff).

, l'initialisation doit être:

unsigned long long int largestIntegerInC = 18446744073709551615ULL;

(Notez le ULL.) Étant donné que largestIntegerInC est de type unsigned long long int, vous devez l'imprimer avec le prescripteur droit de format, qui est "%llu":

$ cat test.c
#include <stdio.h>

int main(void)
{
    unsigned long long int largestIntegerInC = 18446744073709551615ULL;
    /* good */
    printf("%llu\n", largestIntegerInC);
    /* bad */
    printf("%d\n", largestIntegerInC);
    return 0;
}
$ gcc  -std=c99 -pedantic test.c
test.c: In function ‘main’:
test.c:9: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long long unsigned int’

La deuxième printf() ci-dessus est faux, il peut imprimer quoi que ce soit. Vous utilisez "%d", ce qui signifie printf() attend un int, mais obtient un unsigned long long int, qui est (le plus probable) pas la même taille que int. La raison pour laquelle vous obtenez -1 que votre sortie est due à (mauvais) chance, et le fait que sur votre machine, les numéros sont représentés par deux de la représentation du complément.


Pour voir comment cela peut être mauvais, nous allons exécuter le programme suivant:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int main(int argc, char *argv[])
{
    const char *fmt;
    unsigned long long int x = ULLONG_MAX;
    unsigned long long int y = 42;
    int i = -1;
    if (argc != 2) {
        fprintf(stderr, "Need format string\n");
        return EXIT_FAILURE;
    }
    fmt = argv[1];
    printf(fmt, x, y, i);
    putchar('\n');
    return 0;
}

Sur mon macbook, l'exécution du programme avec "%d %d %d" me donne -1 -1 42, et sur une machine Linux, le même programme avec le même format me donne -1 42 -1. Oops.


En fait, si vous essayez de stocker le plus grand nombre de unsigned long long int dans votre variable largestIntegerInC, vous devez inclure limits.h et utiliser ULLONG_MAX. Ou vous devez stocker Assing -1 à votre variable:

#include <limits.h>
#include <stdio.h>

int main(void)
{
    unsigned long long int largestIntegerInC = ULLONG_MAX;
    unsigned long long int next = -1;
    if (next == largestIntegerInC) puts("OK");
    return 0;
}

Dans le programme ci-dessus, les deux largestIntegerInC et next contiennent la plus grande valeur possible pour le type de unsigned long long int.

Autres conseils

Il est parce que vous passez un numéro avec tous les bits à 1. Lorsque interprété comme un numéro signé deux complément, qui fonctionne à -1. Dans ce cas, il cherche probablement à 32 de ces bits au lieu de un tout 64, mais cela ne fait aucune différence réelle.

Dans deux arithmétique de complément, la valeur -1 signé est le même que la plus grande valeur non signée.

Considérons les modèles de bits pour les nombres négatifs en complément à deux (j'utilise 8 bits entiers, mais le modèle applique indépendamment de la taille):

 0 - 0x00
-1 - 0xFF
-2 - 0xFE
-3 - 0xFD

Ainsi, vous pouvez voir que 1 négatif a la configuration binaire de tous 1 ce qui est aussi le modèle binaire pour la plus grande valeur non signée.

Vous avez utilisé un format pour un nombre signé 32 bits, vous avez -1. printf() ne peut pas dire à l'intérieur de la taille du numéro transmis est, il tire juste les premiers 32 bits de la liste varargs et les utilise comme valeur à imprimer. Depuis que vous avez donné un format signé, il imprime cette façon, et 0xffffffff est la représentation de complément à deux de -1.

Vous pouvez (si) voir pourquoi avertissement du compilateur. Sinon, essayez de régler le niveau d'alerte le plus élevé. Avec VS j'ai cet avertissement: avertissement C4245: 'Initialisation': la conversion de '__int64' à '__int64 non signé', signé / non-concordance non signé

.

Non, il n'y a pas de débordement. C'est parce qu'il n'imprime pas la valeur totale:

18446744073709551615 est le même que 0xFFFFFFFFFFFFFFFF. Lorsque les processus printf %d cela, il attrape seulement 32 bits (64 bits ou si elle est un processeur 64 bits) pour la conversion, et ce sont la valeur signée -1.

Si la conversion de printf avait été à la place %u, il montrerait soit 4294967295 (32 bits) ou 18446744073709551615 (64 bits).

Un débordement est lorsqu'une valeur augmente au point où elle ne rentre pas dans le stockage alloué. Dans ce cas, la valeur est alloué très bien, mais est de ne pas être complètement récupération .

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