とくにあぶなくないRiSKのブログ

危ないRiSKのブログだったかもしれない。本当はRiSKだけどググラビリティとか取得できるIDの都合でsscriskも使ったり。

VC++10 の<stdint.h>, <cstdint>はバグっている (2)

<追記>
このエントリは丸ごと間違っているかもしれません。「VC++10 の<stdint.h>, <cstdint>はバグっている (2) へのツッコミ」を参照のこと。
</追記>
Microsoft Visual C++ 2010 の , ヘッダにはまだバグがあります。
以下は の一部を並び替えしたもの。

typedef int int_fast16_t;
#define INT_FAST16_MIN		(-0x7fff - _C2)
#define INT_FAST16_MAX		0x7fff

typedef unsigned int uint_fast16_t;
#define UINT_FAST16_MAX		0xffff

int_fast16_t と INT_FAST16_MIN, INT_FAST16_MAX の組合せにバグがあります。同様に uint_fast16_t と UINT_FAST16_MAX の組合せにバグがあります。
次のように簡単にバグを再現させることができます。

#include<stdint.h>
#include<stdio.h>
int main(){
 {
  int_fast16_t min = INT_FAST16_MIN;
  int_fast16_t negative_overflow = INT_FAST16_MIN - 1;
  int_fast16_t max = INT_FAST16_MAX;
  int_fast16_t positive_overflow = INT_FAST16_MAX + 1;
  printf("%d\n", min);
  printf("%d\n", negative_overflow); // オーバーフローするはずだが…
  printf("%d\n", max);
  printf("%d\n", positive_overflow); // オーバーフローするはずだが…
 }
 {
  uint_fast16_t max = UINT_FAST16_MAX;
  uint_fast16_t overflow = UINT_FAST16_MAX + 1;
  printf("%d\n", max);
  printf("%d\n", overflow); // オーバーフロー(用語不正確。エントリ最下段参照)するはずだが…
 }
}

実行結果:

-32768
-32769
32767
32768
65535
65536

MIN あるいは MAX を超えて表現できているのは明らかです。あちゃー…。
元のソースは修正して

typedef short int_fast16_t;
#define INT_FAST16_MIN		(-0x7fff - _C2)
#define INT_FAST16_MAX		0x7fff

typedef unsigned short uint_fast16_t;
#define UINT_FAST16_MAX		0xffff

とするか

typedef short int_fast16_t;
#define INT_FAST16_MIN		(-0x7fffffff - _C2)
#define INT_FAST16_MAX		0x7fffffff

typedef unsigned short uint_fast16_t;
#define UINT_FAST16_MAX		0xffffffff

とすべきですね。

オーバーフロー

おまけ。オーバーフローの解説。
JISX 3010:2003 6.2.5 型によると

符号無しオペランドを含む計算は,決してオーバフローしない。すな
わち,結果を符号無し整数型で表現できないときは,その型で表現しうる最大値より1 だけ大きい数を法
とする剰余を結果とする。

とあるので,uint_fast16_t 型にオーバーフローという用語を用いたのは本当は間違いです。