読者です 読者をやめる 読者になる 読者になる

Status Code 303 - See Other

Java, C, C++, C#, Objective-C, Swift, bash, perl, ruby, PHP, Python, Scala, Groovy, Go, DevOps, Raspberry Pi など。情報の誤りや指摘・意見などは自由にどうぞ。

C言語 の long int データ型仕様

C 変数

概要

今回、開発環境でテストすると正しいが、本番環境では正しい結果が出力できなかった。
あまりにバカらしい理由ではあるが、戒めのために記述する。

起こった事

環境

この案件では、C 言語で記述したプログラムを本番環境に送って実行する。
私は、Windows 7 64bit のデスクトップで cygwingcc (4.9.3) を使って開発。

問題箇所

ある計算結果を出力するのだが、その結果は結構大きな値になってしまうので、
結果を格納するデータの型に long int を使用。そして、結果の表示において最初以下のように記述していた。

	long int result = (計算部);
	printf("%d", result); // 588491482334(期待値)

すると、出力結果が明らかに小さい。

80962782

そして、自分が フォーマッタを『%d』にしていたミスに気付く。
『%d』→ 『%ld』に修正して、テスト。

	long int result = (計算部);
	printf("%ld", result); // 588491482334(期待値)

出力結果が期待されるものになった。

588491482334

これで問題ないと思い、本番環境に送信して実行。その出力結果。

80962782

なぜか出力が戻った。送信したプログラムを確認したが問題ない。

問題解決フェーズ

計算結果を小さくしてみると正しい値が表示されるため、この現象は計算結果が大きくなった時のみ起こる。
しかし、フォーマッタは『%ld』を指定しているので、問題ないはずだが・・。
試しに『%lu』に変更してみたが効果なし。

今は C 言語の仕様が変わったのか?と思い、C 言語の仕様書を漁るもどこも変更なさそう。

仕方がないので本番環境で試しに、『LONG_MAX』(limits.h)を出力してみた。

2147483647

この瞬間、計算期待値がlong int の表現範囲を超えてることに気づく。
そこで、下記のように修正。

	long long int result = (計算部);
	printf("%lld", result); // 588491482334(期待値)

本番環境でも動作を確認。こんな単純な問題に2時間掛けてしまった。

C 言語のデータ型仕様

この問題の要因を作った、long int の表現範囲を調べる。
まず、一般的には(データ型を参照)

int → 2byte(-32768~32767)を記憶できる
long int → 4byte (-2147483648~2147483647)を記憶できる
long long int → 8byte (-9223372036854775808~9223372036854775807)を記憶できる

まず、ここで既に勘違い。
long int が 8byte だと思ってた。(Java の long 型が 8byte だから)
(付け加えるなら long long int は 16byte だと思ってた)

そして、仕様は結構アバウトであり、基本的に下限だけ決まっている。
つまり、byte 数が大きい分には構わない。実際、私の開発環境では

#include<stdio.h>
#include<limits.h>

int main() {
	printf("INT_MAX:\t%d\n", INT_MAX);
	printf("LONG_MAX:\t%ld\n", LONG_MAX);
	printf("LLONG_MAX:\t%lld\n", LLONG_MAX);
	return 0;
}

その結果。

INT_MAX:        2147483647
LONG_MAX:       9223372036854775807
LLONG_MAX:      9223372036854775807

long int は 8byte だった。しかも、 long long int とデータサイズ同じだった。
普段そんなに大きな値を使わないから、全く意識できていなかった。
反省。

結論

基本的なことではあるけれど、データ仕様は正しく覚える。
環境によってデータサイズが異なる事にも留意する。