Pourquoi 1ul << 64 renvoie-t-il 1 au lieu de 0?

Considérons le code suivant:

// Simply loop over until 64 is hit. unsigned long x = 0; for (int i = 0; i <= 64; i++) { if (i == 64) { x = 1ul << i; printf("x: %d\n", x); } } 

Nous soaps que unsigned long a une largeur de 64 bits et que le décalage gauche de 1 position sur 64 deviendrait 1000 … 000 (64 zéros derrière un) et aurait été tronqué à 0. Toutefois, l’impression réelle donne:

 x: 1 

La chose étrange est, si nous faisons juste

 printf("x: %d\n", (1ul << 64)); 

Cela afficherait 0.

Quelqu’un peut-il expliquer pourquoi ceci est en train de se passer? Pourquoi dans le premier cas, le programme produit par erreur 1 au lieu de 0, mais dans le second c’est correct?

Décaler de la largeur d’un type ou plus provoque un comportement indéfini selon le § 6.5.7 / 3:

  1. Les promotions entières sont effectuées sur chacun des opérandes. Le type de résultat est celui de l’opérande gauche promu. Si la valeur de l’opérande de droite est négative ou est supérieure ou égale à la largeur de l’opérande de gauche promu, le comportement n’est pas défini .

Cela s’explique par le fait que différentes unités centrales implémentent un comportement différent pour les équipes surdimensionnées et qu’il aurait été trop ressortingctif de définir le comportement dans ce cas – de nombreuses équipes nécessiteraient un assemblage supplémentaire. (Bien que cela aurait peut-être dû être défini par la mise en œuvre plutôt que non défini).

Votre observation pourrait s’expliquer par l’utilisation de processeurs de la famille Intel qui “mod 64” matériellement sur la largeur de décalage pour un type 64 bits, de sorte qu’au moment de l’exécution, 1ul << 64 fait la même chose que 1ul << 0 ; mais au moment de la compilation, dans le cas contraire, le compilateur a calculé 1ul << 64 utilisant des règles arithmétiques.