「プログラミング基礎」の授業で,整数の補数表現を理解するために,次のプログラムを動かして確認するという演習を課している.
#include <stdio.h>
int main() {
unsigned char x = 0;
do {
printf("unsigned: %4d "
"signed: %4d\n", x, (char)x);
} while (x++ != 255);
return 0;
}
実際にmacOSで動かしてみると次のような出力になる.
$ gcc file01.c -o file01
$ ./file01
unsigned: 0 signed: 0
unsigned: 1 signed: 1
unsigned: 2 signed: 2
unsigned: 3 signed: 3
(中略)
unsigned: 125 signed: 125
unsigned: 126 signed: 126
unsigned: 127 signed: 127
unsigned: 128 signed: -128
unsigned: 129 signed: -127
unsigned: 130 signed: -126
(中略)
unsigned: 252 signed: -4
unsigned: 253 signed: -3
unsigned: 254 signed: -2
unsigned: 255 signed: -1
$
WindowsのとMacのPCをBYODで持ち込む学生を相手に「プログラミング基礎」の授業をおこなっているので,Cのプログラミングは仮想環境のUbuntu Linuxで教えている.これまで,Ubuntuのgccでも上記と同様の動作を示すので,これまでは問題なかった.
ところが,今年やってみると,どうもうまくいかない(図).
どうも(char)で符号付きchar型にキャストしてくれない様子.これまでの動作,あるいは先に示したmacOSでの挙動と同様とするには,(signed char)と明示的に符号付きだと示さないといけないようになったらしい.
#include <stdio.h>
int main() {
unsigned char x = 0;
do {
printf("unsigned: %4d "
"signed: %4d\n", x, (signed char)x);
} while (x++ != 255);
return 0;
}
いつ,そんな変更があったんだろう.知らなかった.けっこう重要な仕様変更だと思うけど,困ってるひといないのかなあ?
追記:
もともとCの仕様としては,char を signed として扱うか unsigned として扱うかは決められていない,ということだと教えていただきました.なので,明示的に (signed char) とキャストすべし,という対応が正解だとのこと.勉強になりました.
https://gcc.gnu.org/onlinedocs/gcc-5.3.0/gcc/C-Dialect-Options.html#C-Dialect-Options
返信削除Each kind of machine has a default for what char should be. It is either like unsigned char by default or like signed char by default.
とあるので、最初からsigned charを期待してはならないというのが正解だと思います。
コメントありがとうございます.
削除そうですね.勉強になりました.