150 votes

Pourquoi int i = 1024 * 1024 * 1024 * 1024 compiler sans erreur?

La limite de int est de -2147483648 à 2147483647.

Si je saisis

 int i = 2147483648;
 

Eclipse affichera un trait de soulignement rouge sous "2147483648".

Mais si je fais ceci:

 int i = 1024 * 1024 * 1024 * 1024;
 

il compilera bien.

 public class Test {
    public static void main(String[] args) {        

        int i = 2147483648;                   // error
        int j = 1024 * 1024 * 1024 * 1024;    // no error

    }
}
 

Peut-être que c'est une question de base en Java, mais je ne sais pas pourquoi la deuxième variante ne produit aucune erreur.

232voto

arshajii Points 65653

Il n'y a rien de mal avec cette déclaration; vous êtes juste en multipliant les 4 numéros et de l'affecter à un int, il arrive juste à être un dépassement de capacité. Ce qui est différent de l'affectation d'un seul littéral, ce qui serait de limites vérifié à la compilation.

C'est le hors-limites littérale qui provoque l'erreur, pas la cession:

System.out.println(2147483648);        // error
System.out.println(2147483647 + 1);    // no error

Par contre une long littérale serait de compiler fine:

System.out.println(2147483648L);       // no error

Notez que, en fait, le résultat est toujours calculé au moment de la compilation, car 1024 * 1024 * 1024 * 1024 est une expression constante:

int i = 1024 * 1024 * 1024 * 1024;

devient:

   0: iconst_0      
   1: istore_1      

Notez que le résultat (0) est tout simplement chargées et stockées, et pas de multiplication a lieu.


De JLS §3.10.1 (merci à @ChrisK de le signaler dans les commentaires):

C'est une erreur de compilation si une virgule littéral de type int est plus grand que 2147483648 (231), ou si la décimale littérale 2147483648 apparaît n'importe où autre que l'opérande de l'unaire moins de l'opérateur (§15.15.4).

43voto

Cruncher Points 5156

1024 * 1024 * 1024 * 1024 et 2147483648 n'ont pas la même valeur en Java.

En fait, 2147483648 N'est MÊME PAS UNE VALEUR(bien qu' 2147483648L ) en Java. Le compilateur littéralement ne sais pas ce que c'est, ou comment l'utiliser. Donc, il couine.

1024 est une valeur de type int en Java, et une pièce d' int multiplié par un autre valide int, est toujours valide int. Même si ce n'est pas la même valeur que vous attendez, parce que le calcul est en dépassement de capacité.

Exemple

Considérons l'exemple de code suivant:

public static void main(String[] args) {
    int a = 1024;
    int b = a * a * a * a;
}

Voudriez-vous attendre à ce que cela génère une erreur de compilation? Il devient un peu plus glissante maintenant.
Que faire si nous avons mis une boucle avec 3 itérations et multiplié dans la boucle?

Le compilateur est autorisé à optimiser, mais il ne peut pas changer le comportement du programme, alors qu'il est le faire.


Quelques infos sur la façon dont cette affaire est en fait pris en charge:

En Java, et bien d'autres langues, les entiers sera constitué d'un nombre fixe de bits. Des calculs qui ne rentrent pas dans le nombre donné de bits de dépassement; le calcul est essentiellement effectuée le module 2^32 en Java, d'après laquelle la valeur est convertie en un signé entier.

Autres langues ou de l'API de l'utilisation d'une dynamique d'un nombre de bits (BigInteger en Java), soulever une exception ou définir la valeur à une valeur magique comme not-a-number.

15voto

Eric Lippert Points 300275

Je n'ai aucune idée pourquoi le deuxième variante, ne produit pas d'erreur.

Le comportement que vous suggérer-qui est, la production de message de diagnostic lorsqu'un calcul produit une valeur qui est plus grande que la plus grande valeur qui peut être stockée dans un entier , est une fonctionnalité. Pour vous d'utiliser une fonctionnalité, la fonctionnalité doit être pensée, considérée comme une bonne idée, conçu, a précisé, mise en œuvre, testé, documenté et expédiés aux utilisateurs.

Pour Java, une ou plusieurs des choses sur cette liste n'est pas arrivé, et, par conséquent, vous n'avez pas la fonctionnalité. Je ne sais pas lequel; vous auriez à demander à un concepteur Java.

Pour C#, toutes ces choses ne se produisent -- il y a quatorze ans maintenant-et donc le programme correspondant en C# a produit une erreur, puisque C# 1.0.

12voto

piet.t Points 4360

En plus de arshajii la réponse, je veux montrer une chose:

Il n'est pas l' affectation qui provoque l'erreur, mais simplement l'utilisation du littéral. Lorsque vous essayez

long i = 2147483648;

vous remarquerez qu'il provoque également une compilation d'erreur depuis le côté droit est toujours un int-littérale et hors de portée.

Pour les opérations avec int-valeurs (y compris les affectations) peut déborder sans une compilation d'erreur (et sans exécution, erreur), mais le compilateur ne peut tout simplement pas gérer le trop grand littéraux.

4voto

gnasher729 Points 5011

Un: Parce qu'il n'est pas une erreur.

Contexte: La multiplication 1024 * 1024 * 1024 * 1024 va conduire à un dépassement de capacité. Un dépassement de capacité est très souvent un bug. Différents langages de programmation produire un comportement différent lors des débordements se produisent. Par exemple, le C et le C++ appeler "un comportement indéfini" pour les entiers signés, et le comportement est défini entiers non signés (prendre le résultat mathématique, ajoutez - UINT_MAX + 1 , tant que le résultat est négatif, soustraire UINT_MAX + 1 , tant que le résultat est plus grand que UINT_MAX).

Dans le cas de Java, si le résultat d'une opération avec int des valeurs n'est pas dans la plage autorisée, sur le plan conceptuel Java ajoute ou soustrait 2^32 jusqu'à ce que le résultat est dans la plage autorisée. Si la déclaration est tout à fait légal et pas dans l'erreur. Il n'a tout simplement pas produire le résultat que vous pouvez espérer.

Vous pouvez certainement se demander si ce comportement est utile, et si le compilateur devrait vous donner un avertissement. Je dirais personnellement qu'un avertissement serait très utile, mais une erreur serait erronée, car il est légal de Java.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X