Help us understand the problem. What is going on with this article?

Twitterで話題のC++ quiz time!の解説を誰も書かないので書く

問題

こんなツイートが人気を博していた。

#include <iostream>
#include "typename.h"
int main()
{
    short a = 1;
    std::cout << sizeof(+a)["23456"] << std::endl;
}

答えは四択で1,3,4,6のどれですか?というもの。

だれか解説書くだろと思ったが、みんなTwitter上で満足してしまったらしい(見落としてたらすまん)。解説するか。

正解

1になります。

・・・えええっ!?

(私は6だと騙された)

6と誤答した人の脳内回路

誤答したの私だ。アンケートを見ても一番多い。

江添さんがノリノリで誤答を書き込んでいる。

sizeof(+a)["23456"]をどうパースしたかというと

  1. +a
  2. sizeof(+a)
  3. sizeof(+a)["23456"]

とパースしてしまったのだと思う。一般にsizeof演算子は必ず()とつけて使いましょう、と多くの初心者本にかかれており、そして実際多くのC++erが()をつけて使うもんだから、うっかりsizeof(+a)とパースしてしまいそうになるが、operator[]の優先順位がめっちゃ高いことを忘れないでほしい(ブーメラン)

  1. 暗黙変換でintになるよね~
  2. sizeof取ったら4でしょ?
  3. a[b]b[a]とも書けるから文字列の4番めの要素は6

と考えていく。

不正解だ

4と誤答した人の脳内回路

6とほぼ同じだが+aが暗黙変換でintになることを見落とすと4になる

  1. shortでしょ?
  2. sizeof取ったら2でしょ?
  3. a[b]b[a]とも書けるから文字列の4番めの要素は4

と考えていく。

不正解だ

3と誤答した人の脳内回路

ごめんなさい、さっぱりわからない。アンケートでももっとも票数が少ないものの、殆ど無いってわけでもないくらい投票されている。

short a = 1;

だからよくわからんけど文字列の1番めの要素を見に行ってしまったとか??

解説

+a

改めて見ていこう。

short a = 1;

なのでaの型はshort型だ。では+aの型は?

実はint型になる。

単項演算子+の演算の際にintegral promotionという暗黙変換が行われるためだ。

まあ実はint型であるかは重要ではない

(+a)["23456"]

そうだ、ここで誤ってsizeof(+a)を考えてしまうと誤りだ。

operator[]はポインタ演算*(a + b)のsyntax sugarであるというのは割と有名な小話だと思う。

int arr[3] = { 1, 2, 3 };
arr[1]; // => 2
1[arr]; // => 2
*(arr + 1); // => 2

つまりこの場合

(+a)["23456"]"23456"[+a]は等価だ。

aの値は

short a = 1;

より1なので演算結果はchar型の3になる。

sizeof(+a)["23456"]

ようやくsizeof演算子の出番だ。(+a)["23456"]はchar型なので、sizeofを取ると1になる。

sizeof((+a)["23456"])となっていれば引っかかる人は少なかっただろうが・・・。

余談

@Chironian 氏御用達の型名を表示させるマクロTYPENAMEを使いつつ、問題のコードをいじると理解度が増すかもしれない。

#include <iostream>
#include "typename.h"
int main()
{
    short a = 1;
    std::cout
        << sizeof(+a) << std::endl
        << "23456"[4] << std::endl
        << 4["23456"] << std::endl
        << (+a)["23456"] << std::endl
        << TYPENAME((+a)["23456"]) << std::endl
        << sizeof(+a)["23456"] << std::endl;
}

https://wandbox.org/permlink/TT51W7xs3ZEfKpeq

実行結果
4
6
6
3
char
1

教訓

  • sizeof演算子を使うときは()でくくりましょう
  • operator[]の優先順位の高さを忘れない

感想

まんまとひっかかった、くやしい。

License

CC BY 4.0

CC-BY icon.svg

yumetodo
ありきたりなC++erです。最近C++書いていません(あれっ
http://yumetodo.hateblo.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした