warning: implicit declaration of function ‘strcpy’
警告:関数’strcpy’の暗黙の宣言
[-Wimplicit-function-declaration]
■ヘッダファイルとプロトタイプ宣言
➡外部関数の作者の義務
プロトタイプ宣言を
ヘッダファイルに記述する事
➡外部関数使用者の義務
そのヘッダファイルをインクルードして
外部関数を使う事
➡こうする事で相互確認(クロスチェック)が可能となり、
外部関数の宣言と参照で食い違いがあると
コンパイルエラーで弾く事が出来ます
■プロトタイプ宣言が必要
#include <stdio.h>
//ダメ:何も書かない
int main(void)
{
char errmsg[1024];
strcpy(errmsg,strerror(0));
printf("%s\n",errmsg);
}
■標準関数のプロトタイプ宣言を自分で書いては駄目
#include <stdio.h>
int strerror(int);//自分で書いちゃダメ
int main(void)
{
char errmsg[1024];
strcpy(errmsg,strerror(0));
printf("%s\n",errmsg);
}
他人が作った外部関数や標準関数のプロトタイプ宣言を
自分で書いてしまうと関数の使い方が間違っていても
コンパイラがエラーで指摘してくれません。
■プロトタイプ宣言が記載されたヘッダをincludeする
#include <stdio.h>
#include <string.h>
int main(void)
{
char errmsg[1024];
strcpy(errmsg,strerror(0));
printf("%s\n",errmsg);
}
strerror()のプロトタイプ宣言が記述された<string.h>をinclude していないので、strerror()はint 型とコンパイラは解釈します。
strerror()が返却した64bitのアドレスを32bitのint型に切り捨てるので
不正なアドレスを参照しこのプログラムは異常終了する可能性があります。何をinclude したら良いか分からない場合、linux ならば
%man strerror
とコマンド投入すると分かります。
■64bitコンパイラでは一層重要
32bitコンパイラ(ILP32)では
ポインタのサイズも
int のサイズも32bitなので
プロトタイプ宣言無しでもこのプログラムは動いていました。
64bitコンパイラ(LP64)では
ポインタのサイズは64bit
int のサイズは32bit とサイズが異なるため異常終了する可能性があります。
■プロトタイプ宣言の書き方
人が作った外部関数を使う場合は自分でプロトタイプ宣言を記述してはいけません。
必ず外部関数のプロトタイプ宣言が記述されたヘッダファイルをインクルードしてください。
人が作った外部関数のプロトタイプ宣言を自分で記述してしまうと
クロスチェックになりません。
関数の型や引数の型の誤りをコンパイル時に見つける事ができなくなります。
自分で外部関数を作った場合は同様にプロトタイプ宣言をヘッダファイルに記述してヘッダファイルを公開しなければいけません。
■static関数は先に定義すると楽
static 関数の場合は .c ファイルの先頭でプロトタイプ宣言を記述する方法もあるのですが
関数の型や引数に変更があった場合プロトタイプ宣言と関数定義の2か所修正しなかればならず面倒です。
それよりもstatic 関数を使う前にstatic 関数を定義してしまうと
プロトタイプ宣言をわざわざ記述する必要がなくなり
修正も一回で済みます。
参考:
C-FAQ1.7: 絶対に外部関数のプ ロトタイプを. cファイルに置いてはならない。
http://www.kouno.jp/home/c_faq/c1.html#7
https://www.jpcert.or.jp/sc-rules/c-dcl31-c.html