warning: ‘x’ may be used uninitialized in this function
警告:未初期化変数かも
[-Wmaybe-uninitialized]
■スパゲティコード
この警告が出るのは
gccコンパイラが変数の初期化をどこで行っているか
ソースコードを追いきれないからです。
gccコンパイラも追いきれないソースコードなので
普通のプログラマもソースコードを追うのは一苦労です。
このようなソースコードを
スパゲティコード(こんがらがったコード)と言います。
■if文の設定経路に漏れがある時
#include <stdio.h>
char *gomi(int x,int y){
char *ret ;
if(x){
if(y){
ret = "真真";
} else{
ret = "真偽";
}
} else {
if(y){
ret = "偽真";
}
}
return ret ;
}
int main(void){
printf("%s\n",gomi(1,1));
printf("%s\n",gomi(1,0));
printf("%s\n",gomi(0,1));
printf("%s\n",gomi(0,0));
}
変数設定経路に漏れがあります。
xとyが共に0の時
retは設定されず未初期化のまま。
■for文で最大値変数が0の時
#include <stdio.h>
#include <string.h>
int gomi(char *str,int x) {
int match;//max == 0の考慮漏れ
int max = strlen(str);
for(int i = 0;i<max;i++) {
if(str[i] == x) {
match = i ;
break;
} else {
match = -1;
}
}
return match;
}
int main(void){
char ary[] = "jugemujyugemu";
printf("%d\n",gomi(ary,'X'));
printf("%d\n",gomi(ary,'g'));
printf("%d\n",gomi("",'g'));
}
for文第2式の最大値が変数の時、
最大値が0かもしれない。
ループが回らないとmatchは未初期化のまま。
■for文でif文が一度も成立しない時
#include <stdio.h>
int gomi(char *str,int x) {
int match;
for(int i = 0;str[i] != '\0';i++) {
//必ず一度は成立すると思い込むバグ
if(str[i] == x) {
match = i ;
break;
}
}
return match; ;
}
int main(void){
char ary[] = "jugemujyugemu";
printf("%d\n",gomi(ary,'j'));
printf("%d\n",gomi(ary,'u'));
printf("%d\n",gomi(ary,'g'));
printf("%d\n",gomi(ary,'e'));
printf("%d\n",gomi(ary,'M'));//?
}
for文内のif文が一度も成立しないと
matchは未初期化のまま。
■else if の最後にelse が無い時
#include <stdio.h>
char *gomi(int x){
char *ret;
if(x > 0) {
ret = "プラス";
} else if(x < 0) {
ret = "マイナス";
}//else
//多分岐通過時retはゴミ
return ret;
}
int main(void){
printf("%s\n",gomi(1));
printf("%s\n",gomi(-1));
printf("%s\n",gomi(0));
}
else if 多分岐の最後に
else処理を記述して下さい。
x==0の時retは未初期化のまま。
■switch 最後にdefault処理が無い時
#include <stdio.h>
typedef enum{g,c,p} gcp_t;
char *gomi(gcp_t x){
char *ret;
switch(x) {
case g: ret = "グー" ; break;
case c: ret = "チョキ"; break;
case p: ret = "パー"; break;
default:
//何もしない
}
return ret;
}
int main(void){
printf("%s\n",gomi(g));
printf("%s\n",gomi(c));
printf("%s\n",gomi(p));
printf("%s\n",gomi(-1));
}
異常な入力で、
defaultを通過したとき
retは未初期化のままです。
設計上有り得ないと
コンパイラの警告を無視しないで、
エラー処理を追加しましょう。
参考:
EXP33-C. 初期化されていないメモリからの読み込みを行わない
https://www.jpcert.or.jp/sc-rules/c-exp33-c.html
出力用引数よりも戻り値を使用してください。
https://ttsuki.github.io/styleguide/cppguide.ja.html#Output_Parameters
C-FAQ1.30: 自動の寿命を持つ変数の中身は、明示的に初期化しない限りゴミである
http://www.kouno.jp/home/c_faq/c1.html#30
■アンケート