C言語のunsigned short intとunsigned long intの足し算


gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0を利用していたときに起きた出来事です。
型変換を明示してやらないと変な結果になりました。

失敗するコード

#include <stdio.h> //printf(), perror()

int main(int argc, char** argv){
  unsigned long int x=0;
  printf("%lu\n",x);
  for(int i=0;i<1000000;i++){
    unsigned short int y=50000;
    if(i<10){
      printf("%d %lu\n",i,x);
    }
    x+=y*y;
  }
  printf("%lu\n",x);
}

結果は

0
0 0
1 18446744071914584320
2 18446744070119617024
3 18446744068324649728
4 18446744066529682432
5 18446744064734715136
6 18446744062939747840
7 18446744061144780544
8 18446744059349813248
9 18446744057554845952
18444949106413551616

成功するコード

#include <stdio.h> //printf(), perror()

int main(int argc, char** argv){
  unsigned long int x=0;
  printf("%lu\n",x);
  for(int i=0;i<1000000;i++){
    unsigned short int y=50000;
    if(i<10){
      printf("%d %lu\n",i,x);
    }
    x+=(unsigned long int)y*y;
  }
  printf("%lu\n",x);
}

結果は

0
0 0
1 2500000000
2 5000000000
3 7500000000
4 10000000000
5 12500000000
6 15000000000
7 17500000000
8 20000000000
9 22500000000
2500000000000000

自動型変換に頼ってばかりいて落とし穴にハマりました。