C言語の問題①②解答
@kusano_k ksn
https://twitter.com/#!/kusano_k/status/127368325490683904
C言語の問題① ( x==y && x+1==y+2 ) が真(非0)となるxとyの型と値は何でしょう?
C言語の問題② ( x==y && x+1!=y+1 ) が真(非0)となるxとyの型と値は何でしょう?
の解答。
特定の環境でコンパイルできて非0の値になればOK。xとyは別の型でもOK。問題中の式はそのまま使う((bool)x==(bool)y のようにキャストするのはダメ)。C++ではない(適当なクラスを作って演算子のオーバーロードはダメ)。というつもりだった。
私の考えていた解法
#include <stdio.h> int main() { { // (1) double x = 1e100; double y = 1e100; printf( "%d\n", ( x==y && x+1==y+2 ) ); } { // (2) char *x = 0; int *y = 0; printf( "%d\n", ( x==y && x+1!=y+1 ) ); } }
doubleの仮数部の精度は50bit程度なので、大きな数と小さな数を足すと小さな数が無視されてしまう(情報落ち)。
ポインタに整数nを加えると、アドレスはn増えるのではなく、ポインタが指す変数のサイズのn倍増えることを利用する。C++ではエラーになるけど、Cなら異なる型のポインタが比較できる(警告はでるかも)。
見かけた間違い①
bool(_Bool)を使う
0が偽で0以外の値が真ということだろうけど、計算前にint型に変換されてしまうのでダメ。
$ cat test.c #include <stdio.h> int main() { _Bool x=0, y=0; printf( "%d\n", ( x==y && x+1==y+2 ) ); } $ gcc test.c; ./a.out 0
見かけた間違い②
char/short/int/long
例えば、short x=0x7fff, int y=0x7fff ならば x+1=-0x8000, y+1=0x8000 になるということだろうけど、intより小さい型は計算前にintに変換されるというルールがあるのでダメ。
参考
signed/unsigned
例えば、signed int x=0x7fffffff, unsigned int y=0x7fffffff。==での比較の前に、unsignedに変換されてしまうのでダメ。
別解
①
@ucq 勇士Q(β)
https://twitter.com/#!/ucq/status/127374331327164416
int*x=0;short*y=0;みたいな
@dempacat 天下一品だよね…… RT 坦々麺
https://twitter.com/#!/dempacat/status/127374461937786880
double使って①できた。doubleとfloat両方で②やろうとしたら暗黙の型変換でできなかった。ポインタ使ったら、①②同時に満たせた。片方だけってことも可能。 QT @kusano_k: C言語の問題①②
@take_songs たけ (TAKE)
https://twitter.com/#!/take_songs/status/127376160161136640
①short*とint? ②違う方のポインタ同士? RT @kusano_k C言語の問題① ( x==y && x+1==y+2 ) が真(非0)となるxとyの型と値は何でしょう? C言語の問題② ( x==y && x+1!=y+1 ) が真(非0)となるxとyの型と値は
②のようにポインタを使っても解ける。しかも、上手く書くとそのまま②の答えにもなる。x+1==y+3のようにすれば、この解は排除できたのだろうか。
②
@kakkun61 岡本和樹
https://twitter.com/#!/kakkun61/status/127634644064673792
@kakkun61 long long x = INT_MAX; int y = INT_MAX; でうまくいった。
暗黙的にintに変換されてしまうのが問題なので、intよりも大きな型なら良いと。Skypeで別の方からも同じことを言われた。なるほど。