Que se passe-t-il lorsque j’assigne long int à int en C?

Dans un devoir récent, on m’a dit d’utiliser long variable long pour stocker un résultat, car il peut s’agir d’un grand nombre.

J’ai décidé de vérifier s’il est vraiment important pour moi, sur mon système (compilateur intel core i5 / 64-bit Windows 7 / gnu gcc) et j’ai découvert que le code suivant:

 printf("sizeof(char) => %d\n", sizeof(char)); printf("sizeof(short) => %d\n", sizeof(short)); printf("sizeof(short int) => %d\n", sizeof(short int)); printf("sizeof(int) => %d\n", sizeof(int)); printf("sizeof(long) => %d\n", sizeof(long)); printf("sizeof(long int) => %d\n", sizeof(long int)); printf("sizeof(long long) => %d\n", sizeof(long long)); printf("sizeof(long long int) => %d\n", sizeof(long long int)); 

produit la sortie suivante:

 sizeof(char) => 1 sizeof(short) => 2 sizeof(short int) => 2 sizeof(int) => 4 sizeof(long) => 4 sizeof(long int) => 4 sizeof(long long) => 8 sizeof(long long int) => 8 

En d’autres termes, sur mon système, int et long sont les mêmes, et tout ce qui sera trop grand pour que int rest, sera trop long pour durer aussi longtemps.

Le devoir lui-même n’est pas le problème ici. Je me demande comment, sur un système où int < long , devrais-je assigner un int à long?

Je suis conscient du fait qu’il y a de nombreuses questions étroitement liées à ce sujet, mais j’estime que les réponses à ces questions ne me permettent pas de comprendre parfaitement ce qui se passera ou pourra se produire.

Essentiellement, j’essaie de comprendre ce qui suit:

  1. Devrais-je lancer long pour int avant l’affectation, ou puisque long n’est pas un type de données différent, mais simplement un modificateur, il sera considéré comme indigne de l’affectation directe?
  2. Que se passe-t-il sur les systèmes où long > int ? Le résultat sera-t-il indéfini (ou imprévisible) ou les parties supplémentaires de la variable seront-elles omises?
  3. Comment fonctionne le casting de long en int dans C?
  4. Comment l’assignation de long à int fonctionne-t-elle en C quand je n’utilise pas le casting?

    Le langage garantit que int est au moins de 16 bits, long au moins de 32 bits et long peut représenter au moins toutes les valeurs que int peut représenter.

    Si vous affectez une valeur long à un object int , il sera converti implicitement. Il n’y a pas besoin d’une dissortingbution explicite; cela ne ferait que spécifier la même conversion qui va se produire de toute façon.

    Sur votre système, où int et long ont la même taille et la même étendue, la conversion est sortingviale; il copie simplement la valeur.

    Sur un système où long est plus large que int , si la valeur ne tient pas dans un int , le résultat de la conversion est défini par l’implémentation. (Ou, à partir de C99, il peut générer un signal défini par l’implémentation, mais je ne connais aucun compilateur qui le fait réellement.) Ce qui se passe généralement, c’est que les bits de poids fort sont ignorés. sur ça. (Les règles sont différentes pour les types non signés; le résultat de la conversion d’un entier signé ou non signé en un type non signé est bien défini.)

    Si vous devez atsortingbuer en toute sécurité une valeur long à un object int , vous pouvez vérifier qu’il conviendra avant de procéder à l’affectation:

     #include  /* for INT_MIN, INT_MAX */ /* ... */ int i; long li = /* whatever */ if (li >= INT_MIN && li <= INT_MAX) { i = li; } else { /* do something else? */ } 

    Les détails de "quelque chose d'autre" vont dépendre de ce que vous voulez faire.

    Une correction: int et long sont toujours des types distincts, même s’ils ont la même taille et la même représentation. Les types arithmétiques sont librement convertibles, donc cela ne fait souvent aucune différence, mais par exemple, int* et long* sont des types distincts et incompatibles; vous ne pouvez pas assigner un long* à un int* , ou vice versa, sans lancer explicitement (et potentiellement dangereux).

    Et si vous avez besoin de convertir une valeur long en int , la première chose à faire est de reconsidérer la conception de votre code. Parfois, de telles conversions sont nécessaires, mais le plus souvent, elles indiquent que le nom auquel vous avez atsortingbué doit être défini comme long .

    Un long peut toujours représenter toutes les valeurs de int . Si la valeur à scope de main peut être représentée par le type de la variable que vous affectez, la valeur est conservée.

    S’il ne peut pas être représenté, le résultat est formellement non spécifié pour le type de destination signé, tandis que pour le type de destination non signé, il s’agit de la valeur originale modulo 2 n , n étant le nombre de bits de la représentation nécessairement tous les bits de la destination).

    En pratique, sur les machines modernes, vous obtenez également un emballage pour les types signés.

    C’est parce que les machines modernes utilisent la forme de complément à deux pour représenter les entiers signés, sans aucun bit utilisé pour désigner la “valeur invalide” ou toute autre chose, c’est-à-dire tous les bits utilisés pour la représentation des valeurs.

    Avec une représentation de la valeur n bits, toute valeur entière x est mise en correspondance avec x + K * 2 n avec la constante entière K choisie de sorte que le résultat soit dans la plage où la moitié des valeurs possibles sont négatives.

    Ainsi, par exemple, avec 32 bits int la valeur -7 est représentée par le numéro de bitpat -7 + 2 32 = 2 32 -7, de sorte que si vous affichez le nombre que le bitpattern représente sous forme d’entier non signé, vous obtenez une jolie grand nombre.

    La raison pour laquelle cela s’appelle le complément à deux est que cela a du sens pour le système de numération binary, le système de base à deux nombres. Pour le système de numération binary, il y a aussi un complément de note (notez le placement de l’apostrophe). De même, pour le système des nombres décimaux, il y a un complément de dix et un complément à quatre. Avec une représentation du complément à 4 chiffres dix, vous représenteriez -7 comme 10000-7 = 9993. C’est tout.