ioctlの引数
デバッグ情報を付けて再度テストしたところ、ioctl()の引数に問題があることが分かりました。
// 注: バグありコード int axes() const { int value; if (::ioctl(fd_, JSIOCGAXES, &value) != -1) return value; else return 0; }
ioctl()はエラーなら-1を返します。
ここでエラーでないのにvalueに壊れた値が返ってきていました。
ioctl()の呼び出し前にvalueを0にしておくとなぜか正しい値が返ってきて、変だなぁと思ってヘッダを確認したところ、JSIOCGAXESのバッファサイズは8ビットになっていました。
#define JSIOCGAXES _IOR('j', 0x11, __u8) /* get number of axes */
後ろの__u8が引数の(指しているデータの)型のようです。
8ビットだけ書き換えられて、残り24ビットは未初期化のゴミが入っていたわけですね。
というわけで、コードは次のようになりました。
boost::uint8_t axes() const { boost::uint8_t value; if (::ioctl(fd_, JSIOCGAXES, &value) != -1) return value; else return 0; }
ioctl()には文字列か構造体のポインタかintのポインタを渡すものだとばかり思い込んでいました。
教訓: ioctl()にポインタを渡す際はサイズに気をつけましょう。