【GCC】implicit declaration of function '_wtoi' 解決方法
- 問題 : GCC で C コンパイル時の警告文「warning: implicit declaration of function '
_wtoi
' [-Wimplicit-function-declaration] int n = _wtoi(argv[1]);」を解消したい - 答え :
#undef __STRICT_ANSI__
コンパイルする
#include <windows.h> int main() { // コマンドライン引数(1番目)を数値変換して出力 int length; LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &length); int n = _wtoi(argv[1]); TCHAR s[99]; wsprintf(s, TEXT("%d"), n); MessageBox(NULL, s, TEXT(""), MB_OK); return 0; }
警告が出る
コンパイル gcc src.c -std=c11
すると、以下の警告文が表示される。
src.c: In function 'main': src.c:6:3: warning: implicit declaration of function '_wtoi' [-Wimplicit-funct ion-declaration] int n = _wtoi(argv[1]);
この意味は、「暗黙に宣言された関数 _wtoi
を使っています」だ。
インクルードし忘れか?
きっと _wtoi
が宣言されたヘッダファイルをインクルードしていないから、こんな警告をされるのだ。ならば、インクルードしよう。C:\MinGw\include\
内を検索する。
結果はこれだ。
stdlib.h
tchar.h
なので、#include <stdlib.h>
と #include <tchar.h>
を src.c
に追加して再コンパイルするも、同じ警告をされてしまった。(それどころか別のエラーまで発生する始末)
よくよく調べてみると、windows.h
にて、遠回しにこれらのヘッダファイルがインクルードされるようになっていたので、全く意味がなかった。
原因は stdlib.h のソースだった
明示的に宣言しているはずなのに、どうして暗黙の宣言だと警告されてしまうのか。その原因は、stdlib.h
内にある _wtoi
の宣言方法にあった。以下に、当該箇所を示す。
#if !defined (__STRICT_ANSI__) _CRTIMP double __cdecl __MINGW_NOTHROW _wtof (const wchar_t *); _CRTIMP int __cdecl __MINGW_NOTHROW _wtoi (const wchar_t *); _CRTIMP long __cdecl __MINGW_NOTHROW _wtol (const wchar_t *); #endif
#if !defined (__STRICT_ANSI__)
というブロックに囲われて宣言されている。「もし __STRICT_ANSI__
が定義されていないならば、_wtoi
という関数を宣言しますよ」という意味だ。ゆえに、_wtoi
が宣言されたヘッダファイルを正しくインクルードしていても、__STRICT_ANSI__
が定義されていれば、暗黙の宣言になってしまい、警告が出る。
そもそも「暗黙の宣言」とは何か。よくわからないが、#include <stdio.h>
しなくとも printf
が使えるのと同じで、自動的に宣言してくれる機能があるらしい。
GCC コマンドオプションによって結果が変わる
つまり、警告を出さないためには __STRICT_ANSI__
を定義しないようにすればいいことがわかる。どうすれば定義されないようにできるかというと、コンパイル時のオプションで -std=c11
や -std=c99
を指定せず、例えば -std=gnu1x
を指定しておけば定義されなくなる。その証明は、以下のソースコードのコンパイルで行うことができる。
#include <windows.h> int main() { TCHAR s[99]; wsprintf(s, TEXT("%d"), __STRICT_ANSI__); MessageBox(NULL, s, TEXT(""), MB_OK); return 0; }
コンパイル gcc nazo.c -std=c11
して、実行すると、メッセージボックスが現れ、「1」と表示される。
一方で、gcc nazo.c -std=gnu1x
すると、以下のエラーが出てコンパイル失敗する。
nazo.c: In function 'main': nazo.c:4:27: error: '__STRICT_ANSI__' undeclared (first use in this function) wsprintf(s, TEXT("%d"), __STRICT_ANSI__); ^ nazo.c:4:27: note: each undeclared identifier is reported only once for each function it appears in
このことにより、__STRICT_ANSI__
の定義は、-std=c11
なら「有」となり、-std=gnu1x
だと「無」になることがわかる。
強引だが解決できなくはない
ならば、-std=c11
時に行われる __STRICT_ANSI__
の定義を取り消せば、_wtoi
が明示的に宣言されるようになるのであり、その方法として、「ソースコードの最初のほうに #undef __STRICT_ANSI__
を書いておく」というものがある。
#undef __STRICT_ANSI__ #include <windows.h> int main() { // コマンドライン引数(1番目)を数値変換して出力 int length; LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &length); int n = _wtoi(argv[1]); TCHAR s[99]; wsprintf(s, TEXT("%d"), n); MessageBox(NULL, s, TEXT(""), MB_OK); return 0; }
これで警告は出なくなる。
たかが警告だ放っておこう
しかしながら、ヘッダファイルが -std=c11
といった規格指示によって、何らかの意図があって _wtoi
の宣言の有無を自動決定していくれているものを「警告をなくしたいから」という理由だけで影響範囲も考えず __STRICT_ANSI__
の定義を取り消すことはまずいことのきっかけになりそうなにおいを孕んでいる。
たかが警告だ。放っておこう。