すゅん/Суюнのメモ帳/裏紙

またの名をゴミ捨て場

【備忘録】VScodeでC++を使う際に「<bits/stdc++.h>」に赤線が引かれたり「識別子 "cout" が定義されていません」と表示される問題とかの対処法【競プロ】

はじめに

VScode上で<bits/stdc++.h>*1に赤線が引かれたり、「識別子 "cout" が定義されていません」だとか「名前空間 "std" にメンバー "cout" がありません」などと言われたりするものの、しかしコンパイルは通るという謎現象に長い間悩まされておりました。それがやっとこさ解決したので、備忘録として置いておきます。

(gcc を使っている人を対象に書いています。clang や VisualStudio 等(最初から<bits/stdc++.h>が入っているわけではない)を使っている人向けの記事ではありません。)

1. インクルードパスを確認する

参考:gcc のインクルードパスを確認する - ユユユユユ

ターミナル(Powershell 等)にて、以下のコマンドを実行する

gcc -x c++ -v -E /dev/null

するとだいたいこんな感じに出力される

Using built-in specs.
COLLECT_GCC=C:\msys64\mingw64\bin\gcc.exe

(中略)

#include "..." search starts here:
#include <...> search starts here:
 C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/../../../../include/c++/13.1.0
 C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/../../../../include/c++/13.1.0/x86_64-w64-mingw32
 C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/../../../../include/c++/13.1.0/backward
 C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/include
 C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/../../../../include
 C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/include-fixed
End of search list.

(後略)

2. stdc++.h を探す

1.で出力されたパスの中から、「『bits』という名前のフォルダが存在し、さらにその中にstdc++.hというファイルが存在するもの」を探す

  • がんばってさがしましょう。
  • 自分の場合はC:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/../../../../include/c++/13.1.0/x86_64-w64-mingw32にありました。

3. VScodeC/C++ 拡張の設定に追記する

拡張機能の一覧から「C/C++」を探し、歯車のマークをクリックして「拡張機能の設定」を開く

設定項目の中から「Default.IncludePath」を探し、「項目の追加」をクリックして2.で見つけたパスを書き込む

  • 設定項目の上部にある検索欄に「path」と入力すると探しやすいです。

これで解決…と思いきや

ここまでの設定がうまくいっていれば、<bits/stdc++.h>の赤線は消えているはずです。

ただ、ここでまた別のエラーが発生します。「識別子 "cout" が定義されていません」です。

さすがにusing namespace stdはマズいよな、と思ってstd::を付け足してみたところで何も解決しません。

ところが#include <iostream>を付け足すとこのエラーは消えます。

…おかしいですね?#include <bits/stdc++.h> すればiostreamも読み込まれるはずでは?実際コンパイルは普通に通っていますし…。



とりあえず、さっき探したstdc++.hを開いてみましょう。


4. stdc++.h を開き、いくつかの行をコメントアウトする(しなくてもよかった) 再びC/C++ 拡張の設定に追記する

  • だいたい150行目くらいのところに#include <iostream>がありますが…なんか暗く表示されてますね?
  • その上の行を見ていくと…#if _GLIBCXX_HOSTEDという行がありますね。どうやらこれが原因のようです。
  • しかし、自分が調べた範囲では、これの定義に関する情報は全く出てきませんでした…。
    • 定義されているファイルを見つけました。 stdc++.hが存在するファイルにあるc++config.hです。この中の1720行目に#define _GLIBCXX_HOSTED __STDC_HOSTED__という部分があります。
    • __STDC_HOSTED__というのは、「ホスト処理系かどうか」を判定する定数で…まともな実行環境ならだいたい1になります。
    • ではどうすれば認識されるようになるのか…についてはこの後説明します。
  • どうせコンパイルは通るわけですし、コメントアウトしちゃいましょう。

100行目あたりの#if _GLIBCXX_HOSTEDおよび最後の行にある#endif // HOSTEDコメントアウトする

  • ちなみに、他にも暗くなっている行があると思います。#if __cplusplus >= hogehogeで始まっているところですね。
  • これはC++のバージョンによって決まる定数です。
  • 次のコードを参考にして、__cplusplusの値を調べてみましょう。自分の環境では201703Lでした。
  • ところが、VScode上では199711Lとして扱われてしまうようです…。
  • これもコメントアウトしちゃいましょうと、当初は思っていたのですが、いろいろ調べた結果、C/C++拡張の設定の「Default.Compiler Args」に/Zc:__cplusplusを追加すれば正常に判定されることがわかりました。やったね。
    • これは全くの余談ですが、さっき__cplusplusの値を調べるときに使ったプログラムのコードにはコンパイラを判定する部分があり、そこにはgccで使われる__GNUC__というやつが存在します。が、VScodeのデフォルトの設定ではこれは認識されず、代わりにVisualStudioの_MSC_VERが認識されてしまうようです。これまたC/C++拡張の設定の「Default.Compiler Path」を探して「settings.jsonで編集」をクリックし、コンパイラのパスを書き込むと__GNUC__が認識されるようになります。
  • なんかここまで作業してたらいつの間にか#if _GLIBCXX_HOSTEDコメントアウトを外しても#include <iostream>とかが暗くならないようになってました。ええ…(困惑)
  • settings.jsonC_Cpp.default.compilerPathの行をコメントアウトしたら元に戻ったので、おそらくこれが問題を解決する鍵なのでしょう。
  • というわけで正しい手順は以下の通りです。

gccコンパイラのパスをメモする

  • 自分の場合はC:/msys64/mingw64/bin/gcc.exeでした。

C/C++拡張の設定の「Default.Compiler Path」を探して「settings.jsonで編集」をクリックし、コンパイラのパスを書き込む


まとめ

なんかごちゃごちゃしてきたのでもう一度手順をまとめておきます。

  1. インクルードパスを確認する
  2. stdc++.h を探す
  3. VScodeC/C++ 拡張の設定のうち、以下の部分に追記する
    • 「Default.IncludePath」に、2.で見つけたパスを書き込む
    • 「Default.Compiler Path」に、コンパイラのパスを書き込む
    • 「Default.Compiler Args」に、/Zc:__cplusplusを書き込む(必須ではない)

以上です。この記事が誰かの役に立つと良いのですが…。


*1:使うべきかどうかについてはここでは議論しません。