負の数の表現…『0x80000000』は、駄目?
負の数を16進数とかで表現したい場合がある。
平たく言えば十進数に直すのが面倒なのだ…。
例えば16ビットサウンドでのボリュームの変更処理。
オーバーフロー対策で32ビットの『int/long』で処理するのが普通だと思う。
このオーバーフローをチェックするとこんな感じになるかと思う。
short *WaveData;
double Volume;
int Wave = *WaveData;
Wave = ( int )( Wave * Volume );
if( Wave < -32768 )
Wave = -32768;
if( Wave > 32767 )
Wave = 32767;
でも『-32768 / 32767』なんて覚えないので…
if( Wave < 0xFFFF8000 )
Wave = 0xFFFF8000;
if( Wave > 0x00007FFF )
Wave = 0x00007FFF;
なんて書いてしまうと上手く動かない…。
そこで…
if( Wave < ( int )0xFFFF8000 )
Wave = 0xFFFF8000;
if( Wave > ( int )0x00007FFF )
Wave = 0x00007FFF;
と書くと上手く動く…。
謎だ…。(汗)
なので調べてみた…。
#include<stdio.h>
void main( void )
{
__int64 i;
int j;
short k;
for( i = j = k= 0 ; i < 0x100000000 ; i += 0x4000, k += 0x2000 )
{
j = k;
if( j < 0xFFFF8000 )
printf( "8000:%08X\n", j );
if( j > 0x00007FFF )
printf( "7FFF:%08X\n", j );
}
}
結果は、以下の値をループする。
8000:00000000
8000:00002000
8000:00004000
8000:00006000
...
マシン語で見てみると…。
51: if( j < 0xFFFF8000 )
00401077 cmp dword ptr [ebp-0Ch],0FFFF8000h
0040107E jae main+81h (00401091)
…
符号無しで比較している!(汗)
右側優先?それとも符号無し優先?
で『if( j < 0xFFFF8000 )』を『if( j < ( int )0xFFFF8000 )』にすると…
51: if( j < ( int )0xFFFF8000 )
00401077 cmp dword ptr [ebp-0Ch],0FFFF8000h
0040107E jge main+81h (00401091)
符号有りで比較している!
試しに『if( 0xFFFF8000 > j )』とかにしてやってみる…
が、結果変わらず…。
なので符号有りと符号無しの比較では、符号無しで判定されるようだ…。
確認の為に『unsigned int』でも確認してみる。
unsigned int l = 0xFFFF8000;
...
if( j < l )
...
この場合…
『warning C4018: '<' : signed と unsigned の数値を比較しようとしました。』と
きっちり警告がでる!
構わず実行してマシン語を確認すると符号無しで比較していた。
ちなみにこうするとちゃんと符号付きで処理される。
int l = 0xFFFF8000;
...
if( j < l )
...
多分、符号無し優先で判定するのは、仕様なのだろう。
でも、リテラル値が符号無しなら警告を出しても良いんじゃない?
…
こんな使い方をする奴なんかきっと想定外だったのかもしれない…。
結論!
負の数の表現…『0x80000000』は、駄目?
は、駄目!だった…。
2009年7月25日追記----------------
ちなみに『Microsoft Visual Studio 6.0』での事だ。
でも他でも起こるんだろうな…。
| 固定リンク
コメント