zz * 16 と zz<< 4 とで結果が異なる

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
やまっち
記事: 20
登録日時: 10年前

zz * 16 と zz<< 4 とで結果が異なる

#1

投稿記事 by やまっち » 8年前

Windows7 64bit

C:\borland\bcc55\Bin>bcc32
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
Syntax is: BCC32 [ options ] file * = default; -x- = turn switch x off

を使っています。

以下のコードで
zz * 16 と zz<< 4 とで結果が異なる
のですが、その理由を教えて頂きたいです。
よろしくお願いします。

コード:


#include <stdio.h>

void main()
{
	int a,b;

	a= 0xfffffff * 8;
	printf("1st a= %d %x\n", a, a);
	a= a*2;
	printf("2nd a= %d %x\n", a, a);

	printf("----\n");

	b= 0xfffffff * 16; // ここだけおかしい。fffffff0 になってくれない
	printf("b= %d %x\n", b, b);

	printf("----\n");

	a= 0xfffffff << 3;
	printf("1st a= %d %x\n", a, a);
	a= a<<1;
	printf("2nd a= %d %x\n", a, a);

	printf("----\n");

	b= 0xfffffff << 4;
	printf("b= %d %x\n", b, b);

}

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: zz * 16 と zz<< 4 とで結果が異なる

#2

投稿記事 by みけCAT » 8年前

C言語では、符号付き整数のオーバーフローは未定義動作なので、何がおきてもおかしくないです。
BCC 5.5.1で提示されたコードをコンパイルしたexeファイルをobjdumpで逆アセンブルし、main関数に相当しそうな部分を予想して取り出すと

コード:

  401150:	55                   	push   %ebp
  401151:	8b ec                	mov    %esp,%ebp
  401153:	53                   	push   %ebx
  401154:	56                   	push   %esi
  401155:	be 28 a1 40 00       	mov    $0x40a128,%esi
  40115a:	bb f8 ff ff 7f       	mov    $0x7ffffff8,%ebx
  40115f:	53                   	push   %ebx
  401160:	53                   	push   %ebx
  401161:	56                   	push   %esi
  401162:	e8 85 27 00 00       	call   0x4038ec
  401167:	83 c4 0c             	add    $0xc,%esp
  40116a:	03 db                	add    %ebx,%ebx
  40116c:	53                   	push   %ebx
  40116d:	53                   	push   %ebx
  40116e:	8d 46 0e             	lea    0xe(%esi),%eax
  401171:	50                   	push   %eax
  401172:	e8 75 27 00 00       	call   0x4038ec
  401177:	83 c4 0c             	add    $0xc,%esp
  40117a:	8d 56 1c             	lea    0x1c(%esi),%edx
  40117d:	52                   	push   %edx
  40117e:	e8 69 27 00 00       	call   0x4038ec
  401183:	59                   	pop    %ecx
  401184:	b8 01 00 00 00       	mov    $0x1,%eax
  401189:	50                   	push   %eax
  40118a:	50                   	push   %eax
  40118b:	8d 56 22             	lea    0x22(%esi),%edx
  40118e:	52                   	push   %edx
  40118f:	e8 58 27 00 00       	call   0x4038ec
  401194:	83 c4 0c             	add    $0xc,%esp
  401197:	8d 4e 2c             	lea    0x2c(%esi),%ecx
  40119a:	51                   	push   %ecx
  40119b:	e8 4c 27 00 00       	call   0x4038ec
  4011a0:	59                   	pop    %ecx
  4011a1:	bb f8 ff ff 7f       	mov    $0x7ffffff8,%ebx
  4011a6:	53                   	push   %ebx
  4011a7:	53                   	push   %ebx
  4011a8:	8d 46 32             	lea    0x32(%esi),%eax
  4011ab:	50                   	push   %eax
  4011ac:	e8 3b 27 00 00       	call   0x4038ec
  4011b1:	83 c4 0c             	add    $0xc,%esp
  4011b4:	03 db                	add    %ebx,%ebx
  4011b6:	53                   	push   %ebx
  4011b7:	53                   	push   %ebx
  4011b8:	8d 56 40             	lea    0x40(%esi),%edx
  4011bb:	52                   	push   %edx
  4011bc:	e8 2b 27 00 00       	call   0x4038ec
  4011c1:	83 c4 0c             	add    $0xc,%esp
  4011c4:	8d 4e 4e             	lea    0x4e(%esi),%ecx
  4011c7:	51                   	push   %ecx
  4011c8:	e8 1f 27 00 00       	call   0x4038ec
  4011cd:	59                   	pop    %ecx
  4011ce:	b8 f0 ff ff ff       	mov    $0xfffffff0,%eax
  4011d3:	50                   	push   %eax
  4011d4:	50                   	push   %eax
  4011d5:	8d 56 54             	lea    0x54(%esi),%edx
  4011d8:	52                   	push   %edx
  4011d9:	e8 0e 27 00 00       	call   0x4038ec
  4011de:	83 c4 0c             	add    $0xc,%esp
  4011e1:	5e                   	pop    %esi
  4011e2:	5b                   	pop    %ebx
  4011e3:	5d                   	pop    %ebp
  4011e4:	c3                   	ret    
となりました。
定数同士の計算式は、その結果で埋め込まれていることがわかります。
さらに、コンパイル時に

コード:

raw1.c:
Warning W8056 raw1.c 14: Integer arithmetic overflow in function main
という警告が出ました。
したがって、コンパイラが未定義動作である符号付き整数のオーバーフローを検出し、適当な値で置き換えたのであると推測できます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

やまっち
記事: 20
登録日時: 10年前

Re: zz * 16 と zz<< 4 とで結果が異なる

#3

投稿記事 by やまっち » 8年前

みけCAT さん、以前は大変お世話になりました。
今回も回答して頂いて、ありがとうございました。

確かにコンパイル時に
> 警告 W8056 test.c 15: 整数の算術オーバーフロー(関数 main )
が出ていました。記載すべき情報が抜けてしまい、すみませんでした。

逆アセンブルするような高度な解析方法もあるんですね。
ありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る