warning: operation on ‘x’ may be undefined
warning: multiple unsequenced modifications to ‘x’
警告: ‘x’ に対する演算は未定義動作の可能性があります。
[-Wsequence-point]
■この記事の概要
この記事では、C言語でx = x++
のようなコードが未定義動作を引き起こす理由を解説しています。式内で同じ変数が複数回更新されると、評価順序が定義されないため予測不能な結果が生じます。この動作がどのようにバグを招くかや、回避するための正しいコーディング手法について具体例を交えて説明しています。
■C言語仕様で動作が定義されていない「未定義の動作」はバグです
未定義動作とは文字道理コンパイラがどのように動くか定義されていないので
動作保証がありません。
プログラマが意図した通り
動くかもしれませんし
動かないかもしれません。
たまたま意図した通り動いたとしても
動作保証がありません。
簡単に言うと、
未定義動作はバグです。
■x=x++は未定義動作でバグです
#include <stdio.h>
int main(void){
int x = 1234 ;
x = x++ ;
printf("%d\n",x);
}
感覚的には問題なさそうですが
変数 x を一式の中で2回更新しているので、
C言語規格で未定義動作のバグとなります。
x =x++の式では
++ で更新
= で更新
合計2回 x を更新しているので
未定義動作のバグとなります。
■i=i=0も未定義動作でバグです
#include <stdio.h>
int main(void){
int i;
int j;
i = i = 0;
printf("%d\n",i);
}
感覚的には問題なさそうですが
変数 i を一式の中で2回更新しているので、
これも未定義動作のバグとなります。
■教科書に出ている未定義動作
#include <stdio.h>
int main(void){
int buf[10];
int i = 0;
while(i<10){
buf[i] = i++;
}
}
教科書「プログラミング言語C」の
2.12章 優先度と評価順序で紹介されている
未定義動作です。
■カウンターストップと未定義動作
#include <stdio.h>
int main(void){
int x = 0 ;
for(int i = 0 ; i < 32;i++){
//一式内で同一変数を2回以上更新
x = (x < 16)? ++x : x ;
printf("x = %d\n",x);
}
}
これはカウンターが上限値に達したら
上限値でカウントをストップしたい時に
よく発生する未定義動作です。
x = (x < 16)? ++x : x ;の行で
++x で一回更新
x= で一回更新
合計2回xを更新しているので
未定義動作のバグとなります。
参考:
EXP30-C. 副作用が発生する式の評価順序に依存しない
https://www.jpcert.or.jp/sc-rules/c-exp30-c.html
C-FAQ 3.2: 同じオブジェクトが2回変更された
http://www.kouno.jp/home/c_faq/c3.html#2