LoginSignup
5
4

More than 5 years have passed since last update.

Serial.printの挙動について調べてみた

Last updated at Posted at 2016-05-04

加速度センサーから取ってきた値をシリアルモニタに表示するときに、ビット演算を使って2個のレジスタの値を合体させていました。

x = readRegister(REG_X1) | (readRegister(REG_X2) << 8);
Serial.println(x, HEX);

1個目のレジスタが下位8ビット、2個目のレジスタが上位8ビットなので、2個目を8ビット左シフトさせてから合体させてやればいいだろうと。

こう書いていると、まれにおかしな値が出ることが。

38
47
FFFFFFF8  // ←?
FFFFFFF7  // ←?

センサーを動かしながら値を取っているので、大きく変動することはあると思うんですが、そもそも桁数がおかしい。

実験してみた

どうやら2個目のレジスタがFFとかFEあたりのときに発生しているらしく、シフト演算と関係ありそうなので実験してみました。

int a = 255;                  // 0xFF
Serial.println(sizeof(int));  // => 2 つまりintは16ビット

Serial.println(a << 4, HEX);  // =>      FF0 ←わかる
Serial.println(a << 8, HEX);  // => FFFFFF00 ←?
Serial.println(a << 12, HEX); // => FFFFF000 ←??
Serial.println(a << 16, HEX); // =>        0 ←わかる(あふれた)

sizeofで返ってくる値からも、intは16ビットと思われるので、FFFFFF00みたいな桁数はおかしい。

更に実験してみた

リファレンスに関係がありそうな記載があったので、更に実験してみました。

<< (左シフト) >> (右シフト)

最上位ビットが1のxを右シフトするとき、結果はxの型に依存します。xがint型ならば最上位ビットは符号ビットですが、深遠な歴史的経緯に基づき、その符号ビットが右側にコピーされていきます。

今回やってるのは 左シフト なんだけど、何だか挙動が似てるぞ……!
というわけで、unsigned intでやってみました。

unsigned int b = 255;
Serial.println(b << 4, HEX);  // =>  FF0
Serial.println(b << 8, HEX);  // => FF00
Serial.println(b << 12, HEX); // => F000
Serial.println(b << 16, HEX); // =>    0
Serial.println();

思った通りの動きになってる!!
けど、今回のとは関係ない気がする。1で埋められるのは右シフトの時ですし。

原因究明

もしかしたらSerial.printで表示するときに何かしているのでは?と思い、実装箇所を探してみました。(正直、探すのに一番時間かかった……。)

Arduino/hardware/arduino/avr/cores/arduino/Print.cpp

Print.cpp
size_t Print::print(int n, int base)
{
  return print((long) n, base);
}

longにキャストしてる!!
何だか分かってきたかも……。

つまり、こういうことだったみたいです。

  1. intの変数に 255 を入れる(16ビットintなので 0x00FF になる)
  2. 8ビット左シフトすると、 0xFF00 になる
  3. 普通のintは固定小数点数なので、最上位ビットが1だとマイナスの値になっちゃう( -256 を表す)
  4. longにキャストしたときに、同じ-256を表すように隙間を1で埋められる
  5. 16進表記すると FFFFFF00 って表示される

分かってしまえば凄く単純で初歩的な事でした。

今回の教訓

  • シフト演算するときはunsigned intにする
  • intlongのサイズが色々あることを意識する
5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4