2014年7月5日土曜日

Perlのprintf("%d")の落とし穴

古いマシンで、32bit版のCentOS6を使っているのですが、その環境で手持ちのPerlスクリプトの出力値がおかしく(負値になる)、つまるところ2Gを越える整数値をprintf("%d")で表示しようとすると、オーバーフローするためのようでした。
[root@hoge ~]# cat /etc/redhat-release 
CentOS release 6.4 (Final)
[root@hoge ~]# uname -p
i686
[root@hoge ~]# perl -e '$a=1024*1024;$b=1024;printf("%d\n",$a*$b);'
1073741824
[root@hoge ~]# perl -e '$a=1024*1024;$b=1024*2;printf("%d\n",$a*$b);'
-2147483648
[root@hoge ~]# perl -e '$a=1024*1024;$b=1024*3;printf("%d\n",$a*$b);'
-1073741824
[root@hoge ~]# perl -e '$a=1024*1024;$b=1024*4;printf("%d\n",$a*$b);'
-1
[root@hoge ~]# perl -e '$a=1024*1024;$b=1024*5;printf("%d\n",$a*$b);'
-1
現象はわかりましたが、ちゃんと表示できるようにするにはどうしたらいいのか、しばし格闘したのち、%sを使えば、よきに計らってくれることがわかりました。Perlよ、ありがとう。
[root@hoge ~]# perl -e '$a=1024*1024;$b=1024*2;printf("%s\n",$a*$b);'
2147483648
[root@hoge ~]# perl -e '$a=1024*1024;$b=1024*3;printf("%s\n",$a*$b);'
3221225472
[root@hoge ~]# perl -e '$a=1024*1024;$b=1024*4;printf("%s\n",$a*$b);'
4294967296
[root@hoge ~]# perl -e '$a=1024*1024;$b=1024*5;printf("%s\n",$a*$b);'
5368709120
あるいは、いったん変数に入れれば、次のように書けます。場合によっては、こちらのほうがいいかも。
[root@hoge ~]# perl -e '$a=1024*1024;$b=1024*2;$c=$a*$b;print("$c\n");'
2147483648
[root@hoge ~]# perl -e '$a=1024*1024;$b=1024*3;$c=$a*$b;print("$c\n");'
3221225472
[root@hoge ~]# perl -e '$a=1024*1024;$b=1024*4;$c=$a*$b;print("$c\n");'
4294967296
[root@hoge ~]# perl -e '$a=1024*1024;$b=1024*5;$c=$a*$b;print("$c\n");'
5368709120
もちろん、64bit環境では%dであっても、負にはなりません。

2 件のコメント:

  1. perldoc の printf の項にも書いてある通り、特別な書式指定が欲しいのでない限り、普段は print で書く癖をつけておいたほうが無難でしょうね。
    perl -e '$a=1024*1024;$b=1024*5;print $a*$b . "\n"'

    返信削除
    返信
    1. over80 様、アドバイスをありがとうございます。単純な出力をする場合、print のほうを使うことが推奨されているのですね。また、ご指摘の書き方なら、$c は不要ですね。どうもありがとうございました。

      削除

人気ブログランキングへ にほんブログ村 IT技術ブログへ