C言語関係掲示板

過去ログ

No776 演算中のオーバフロー

[戻る] [ホームページ]
No.9602

演算子の結合規則と優先順位
投稿者---とおり(2003/10/07 15:06:17)


以下のテストプログラムのAの結果が理解できません。
Bのように動作することを期待したのですが、実際はCのような動作になりました。
結合規則と優先順位を考えるとやっぱりBになるように思えるのですが、
どう考えればいいのでしょうか?

/*
    ・LSIC、BCBでの出力結果
        A:20000 + 30000 = 50000
        B:20000 + 30000 = -15536
        C:20000 + 30000 = 50000
*/
#include <stdio.h>

int main(void)
{
    short x = 20000;
    short y = 30000;
    long ansA, ansB, ansC;

    ansA = x + y;
    ansB = (short)(x + y);
    ansC = (long)x + y;

    printf("A:%hd + %hd = %ld\n", x, y, ansA);
    printf("B:%hd + %hd = %ld\n", x, y, ansB);
    printf("C:%hd + %hd = %ld\n", x, y, ansC);

    return 0;
}


No.9603

Re:演算子の結合規則と優先順位
投稿者---とおり(2003/10/07 15:14:08)


同じようにlongとdoubleでやってみたところ、今度はBと同じ結果になりました。
これを見てなんとなく理解できたような気がします。
もし16bit環境だったらshortとlongの場合もBと同じ結果になったんですね。
自己完結申し訳ありません。

/*
    ・LSIC、BCBでの出力結果
        A:1000000000 + 2000000000 = -1294967296.000000
        B:1000000000 + 2000000000 = -1294967296.000000
        C:1000000000 + 2000000000 = 3000000000.000000
*/
#include <stdio.h>

int main(void)
{
    long x = 1000000000;
    long y = 2000000000;
    double ansA, ansB, ansC;

    ansA = x + y;
    ansB = (long)(x + y);
    ansC = (double)x + y;

    printf("A:%ld + %ld = %f\n", x, y, ansA);
    printf("B:%ld + %ld = %f\n", x, y, ansB);
    printf("C:%ld + %ld = %f\n", x, y, ansC);

    return 0;
}


No.9605

Re:演算子の結合規則と優先順位
投稿者---たか(2003/10/07 15:52:42)


>もし16bit環境だったらshortとlongの場合もBと同じ結果になったんですね。

同じにはなりません。処理系のlimits.hを覗いてみてください。
longはどんな処理系でも少なくとも32ビット長を確保する事になってい
ます。それに対しshortはLSI-Cでは16ビット長となっています。short
のLSI-CでのSHRT_MAXは+32767です。つまり演算の結果が32767を超える
とオーバーフローを起こし、結果が正しくなくなる事を示しています。

今のプログラムでは結果が50000となりますからLSI-Cのshortではオー
バーフローを発生して結果が狂っていたわけです。

もしLSI-Cでもunsigned shortを使用していれば、USHRT_MAXは65535
ですので正しい結果が出ます。但し表示の書式文字列は"%u"となります。

No.9604

Re:演算子の結合規則と優先順位
投稿者---YuO(2003/10/07 15:45:46)


    short x = 20000;
    short y = 30000;
    long ansA, ansB, ansC;

    ansA = x + y;


え〜っと。
ansA = x + y;

ansA = (long)((int)x + (int)y);
だから……あれ?
LSI-Cでも50000になりました?

intが16bitの処理系では-15536に,
intがそれより大きい処理系では50000に,
それぞれなるはずですが。

No.9607

Re:演算子の結合規則と優先順位
投稿者---とおり(2003/10/07 16:37:31)


返信ありがとうございます。
なんとなく理解したつもりが、またわからなくなってきました。
> もし16bit環境だったらshortとlongの場合もBと同じ結果になったんですね。
と書きましたが、LSICがその16bit環境にあたるんですね。
LSICのintが32bitだと思ってて理解した気になっていました。

>たかさん
> 今のプログラムでは結果が50000となりますからLSI-Cのshortではオー
> バーフローを発生して結果が狂っていたわけです。
結果が狂うことを期待したのに狂わなかったのはなぜか、と思い質問しました。

>YuOさん
> ansA = (long)((int)x + (int)y);
> だから……あれ?
> LSI-Cでも50000になりました?
やっぱりこう解釈されるんですよね。
LSICの定義とログを以下に貼っておきます。

--------------------------------
#define INT_MAX     +32767
#define INT_MIN     -32767
--------------------------------
C:\WINDOWS\デスクトップ>lcc
LSI C-86 Compiler ver 3.30c  [Aug 19 1993]
Copyright (C) 1988-1993 LSI Japan Co., Ltd.  All Rights Reserved.

---- S-Model ONLY ----
Usage: lcc [-afile][-c][-Dname[=value]][-g][-h][-Idir][-jN][-k linkopt]
           [-llibrary][-Ldir][-m][-mslink][-nX][-noconf][-nomslink]
           [-o output][-O][-p][-S[C]][-Tdir][-vN][-wN][-Xdir][-yN][-z]
           sourcefile...

soucefile: one of: *.c *.a86 *.asm *.obj *.lib

C:\WINDOWS\デスクトップ>lcc test

C:\WINDOWS\デスクトップ>test
A:20000 + 30000 = 50000
B:20000 + 30000 = -15536
C:20000 + 30000 = 50000

C:\WINDOWS\デスクトップ>


No.9608

Re:演算子の結合規則と優先順位
投稿者---とおり(2003/10/07 17:24:02)


以下の結果を見ると、計算結果がオーバーフローするときは自動的にlongになっているようです。
そういう動作は定数でしかおこらないと思っていましたが、この動作は規格通りなんでしょうか?
4−1.暗黙の型変換、を読み直しましたが今回の動作を理解できませんでした。

/*
    ・LSICでの出力結果
        A:20000 + 30000 = 50000
        B:20000 + 30000 = 50000
        C:20000 + 30000 = 50000
        D:20000 + 30000 = 50000
        E:20000 + 30000 = -15536
*/
#include <stdio.h>

int main(void)
{
    short x = 20000;
    short y = 30000;
    long ansA, ansB, ansC, ansD, ansE;

    ansA = x + y;
    ansB = (int)x + (int)y;
    ansC = ((int)x + (int)y);
    ansD = (long)((int)x + (int)y);
    ansE = (long)(int)((int)x + (int)y);

    printf("A:%hd + %hd = %ld\n", x, y, ansA);
    printf("B:%hd + %hd = %ld\n", x, y, ansB);
    printf("C:%hd + %hd = %ld\n", x, y, ansC);
    printf("D:%hd + %hd = %ld\n", x, y, ansD);
    printf("E:%hd + %hd = %ld\n", x, y, ansE);

    return 0;
}


No.9613

Re:演算子の結合規則と優先順位
投稿者---たか(2003/10/07 19:46:06)


>以下の結果を見ると、計算結果がオーバーフローするときは自動的にlongになっているようです。
>そういう動作は定数でしかおこらないと思っていましたが、この動作は規格通りなんでしょうか?

違います。ANSI-Cではオーバーフローを起こした時の動作は機種依存と
なっています。LSI-C86はx86上で動く処理系であり、x86は符号付き整数
演算ではオーバーフローが起きてもOFフラグをセットするだけであり、
例外は起こしません。もし処理系によってOFフラグをチェックするように
なっていればそこで止まるでしょう。

但し、LSI-C86ではマニュアルに次の一節があります。
>+ 整数の格上げ(Integral promotion)ルールがANSIの定義とは若干異な
>っています。

そして、演算部分を-SCオプションで出力すると次のようになっていまし
た。

	MOV	CX,20000
	MOV	SI,30000
;{
;    short x = 20000;
;    short y = 30000;
;    long ansA, ansB, ansC, ansD, ansE;
;
;    ansA = x + y;
	MOV	AX,CX
	CWD
	MOV	BX,AX
	MOV	DI,DX
	MOV	AX,SI
	CWD
	ADD	BX,AX
	ADC	DI,DX
	MOV	[BP-4].W,BX
	MOV	2[BP-4].W,DI

CWDというのがそうで、short同士の演算なのにlongまたはunsigned long
にしてから演算しているんですね。ANSI-Cの定義通りであれば、こうは
なりません。どうやらLSI-C86は代入しようとする変数の型に合わせて
右辺値をキャストしてから演算するように思えます。