C++ クイズの解説
先日、こんな投稿があり、C++ 界隈で話題だったようです。
C++ quiz time! Without checking, what does this print (assume an LP64 / LLP64 system):
— Richard Smith (@zygoloid) March 18, 2019
short a = 1;
std::cout << sizeof(+a)["23456"] << std::endl;
short a = 1; std::cout << sizeof(+a)["23456"] << std::endl;
上のコードで表示されるのはいったい何かという C++ のクイズです。
奇怪なコードですが警告やエラーにはなりません。
多分 "Without checking" で正解できた人はかなり少ないのではないかと思うのですが……。
正解
正解は 1 が表示されます。
解説
まず、a[b]
はb[a]
と同じです。
これは何故かというと、a[b]
は*(a + b)
のシンタックスシュガー*1に過ぎず、また二項の + 演算子は交換法則が成り立つので*(a + b)
は*(b + a)
と同じになるからです。
// 全部同じ "hoge"[1]; *("hoge" + 1); *(1 + "hoge"); 1["hoge"];
ちなみに文字列リテラルの値は、その文字列の先頭へのポインタになります。
const char* str = "hoge"; // 全部同じ str[1]; *(str + 1); *(1 + str); 1[str];
上のように書けばわかりやすいのではないでしょうか。
次に、+a
は値としての変化はないのですが、暗黙の型変換により short 型から int 型に格上げされます。
ただしこれはひっかけで、答えには影響を及ぼしません。
そして、sizeof 演算子について。
指定された式または型のバイト単位のサイズを返す演算子ですが、オペランドが式の場合の括弧はなくても構いません。
sizeof(int); // 括弧が必要 sizeof 0; // 括弧がなくてもOK
また、sizeof 演算子よりも添字演算子の方が優先順位が高いため、sizeof(a)[b]
はsizeof((a)[b])
と同じです。
ここを(sizeof(a))[b]
であると無意識に勘違いしてしまった人は多そうです。見事に勘違いしてました。
というわけで、sizeof(+a)["23456"]
という式がどう解釈されるかというと、
sizeof(+a)["23456"]; sizeof("23456"[+a]); sizeof("23456"[1]); sizeof('3');
となり、char 型のサイズを返すことになり 1 が表示されるというわけでした。*2
ちなみに筆者の思考回路では
sizeof(+a)["23456"]; sizeof(short)["23456"]; // +a が int になることを忘れ… 2["23456"]; // 優先順位に気が付かず… "23456"[2]; '4'
4 になるのかと思いました。