static で値を0以外に初期化するとバグが起きます
-
あsdf
static で値を0以外に初期化するとバグが起きます
OpenNI(キネクト)、OpenCV、OpenGL、OpenALを使っています。
staticで変数を0以外に初期化すると、光源の設定が無効になります。0にすると、有効となります。
その変数を定義した場所は、あるサブルーチンの中で、プログラム中ではその関数を使っていません。
しかし、その使っていない関数の中のstatic変数を0以外で初期化すると、無効になるのです。また、グローバル変数を0以外で初期化しても同様です。
普通、関数を実行していなければ、プログラムには影響しないと思うのですが、今回はstaticでプログラム開始前に静的領域に格納しているため、このようなバグが起きたのだと思います。ただ、理由が全くわかりません。
静的領域の容量をオーバーしてしまったためにこのようなバグが起きたのでしょうか?
staticではなく、普通にプログラム領域に変数を格納(ローカル変数)すると、大丈夫です。
staticで変数を0以外に初期化すると、光源の設定が無効になります。0にすると、有効となります。
その変数を定義した場所は、あるサブルーチンの中で、プログラム中ではその関数を使っていません。
しかし、その使っていない関数の中のstatic変数を0以外で初期化すると、無効になるのです。また、グローバル変数を0以外で初期化しても同様です。
普通、関数を実行していなければ、プログラムには影響しないと思うのですが、今回はstaticでプログラム開始前に静的領域に格納しているため、このようなバグが起きたのだと思います。ただ、理由が全くわかりません。
静的領域の容量をオーバーしてしまったためにこのようなバグが起きたのでしょうか?
staticではなく、普通にプログラム領域に変数を格納(ローカル変数)すると、大丈夫です。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: static で値を0以外に初期化するとバグが起きます
配列で添字範囲外をアクセスしているか、ポインタがとんでもないところを指している可能性があります。
VC++などのデバッガの機能でその変数を参照した時にデバッグブレークする機能がありますので試してみると良いと思います。
VC++などのデバッガの機能でその変数を参照した時にデバッグブレークする機能がありますので試してみると良いと思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
-
あsdf
Re: static で値を0以外に初期化するとバグが起きます
おっしゃるとおりだと思い、いろいろ探してみたのですが、見つかりませんでした。
なぜ、0で初期化するとうまくいくのに、0以外だとダメなのでしょうか。
ここが物凄く気になります。
おそらく、格納される場所が違うのでしょうが。。。
なぜ、0で初期化するとうまくいくのに、0以外だとダメなのでしょうか。
ここが物凄く気になります。
おそらく、格納される場所が違うのでしょうが。。。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: static で値を0以外に初期化するとバグが起きます
それはデバッガの機能でデータブレークされたと言うことでしょうか?あsdf さんが書きました:おっしゃるとおりだと思い、いろいろ探してみたのですが、見つかりませんでした。
なぜ、0で初期化するとうまくいくのに、0以外だとダメなのでしょうか。
ここが物凄く気になります。
おそらく、格納される場所が違うのでしょうが。。。
目視で探しても限界があり探し出すことは困難です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
-
あsdf
Re: static で値を0以外に初期化するとバグが起きます
すいません。実はこれは友達のプログラムで、質問されただけなんです。
友達は、現状でも動くからいいと言っていて・・・
自分としては、なぜこのようなことが起きるのかということが知りたいだけなんです。
解決法ではなく、理由を教えていただきたいです。。。
友達は、現状でも動くからいいと言っていて・・・
自分としては、なぜこのようなことが起きるのかということが知りたいだけなんです。
解決法ではなく、理由を教えていただきたいです。。。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: static で値を0以外に初期化するとバグが起きます
staticな変数はメモリ上の静的領域に配置されますが、ここには色々なファイルや関数のstaticな変数が集められています。あsdf さんが書きました:すいません。実はこれは友達のプログラムで、質問されただけなんです。
友達は、現状でも動くからいいと言っていて・・・
自分としては、なぜこのようなことが起きるのかということが知りたいだけなんです。
解決法ではなく、理由を教えていただきたいです。。。
ここには当然ながらstaticな配列なども近いメモリ空間に配置されていますので、もし配列アクセスで添字範囲外アクセスをすると予想もしない変数の値を見てしまう可能性があります。
あるいは、static変数をポインタ参照している場合にポインタ値が誤操作されれば何処の変数を参照するかは予想できません。偶然ポインタ変数がstatic変数のアドレスを指した可能性もあります。
更に配列の添字やポインタ値の異常は連鎖する可能性もあるので引き金となった物はもっと別の配列操作やポインタ処理かも知れません。
参考プログラム。すべての環境での再現性はありません。 cygwin gcc 4.3.4 gcc main.cでコンパイル・リンク。
#include <stdio.h>
void func(void)
{
static int a = 99;
}
int main()
{
static int b[3] = { 3,5,7 };//やべっintを書き忘れ。
int i;
for( i=-1 ; i<3 ; i++ ) {
printf( "b[%d]=%d\n", i, b[i] );
}
}
ましてや再現性が確実なら後々のためにバグを取っておくほうが技術力アップにもつながります。
興味があるなら、その友人のプログラムのバグの原因を調べさせてもらってはどうでしょうか? 良い教材だと思うんですけどね。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: static で値を0以外に初期化するとバグが起きます
ポインタも織り交ぜたバージョン。
実行結果
#include <stdio.h>
void func(void)
{
static int a = 99;
}
int main()
{
static int b[3] = { 3,5,7 };
int *px = &b[1];
int i;
for( i=-1 ; i<4 ; i++ ) {
printf( "b[%d]=%d\n", i, b[i] );
}
printf( "*(px)=(%p)=%d\n", px, *(px) );
printf( "*(px-2)=(%p)=%d\n", px-2, *(px-2) );
printf( "*(px+2)=(%p)=%d\n", px+2, *(px+2) );
}
void func2(void)
{
static int c = 1111;
}
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
-
あsdf
Re: static で値を0以外に初期化するとバグが起きます
VisualStudio2010で同様のプログラムを実行してみると、同じ結果が得られました。
static変数は定義された順に静的領域に連続的に格納されるということでしょうか?
static変数は定義された順に静的領域に連続的に格納されるということでしょうか?
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: static で値を0以外に初期化するとバグが起きます
その保証はありません。あsdf さんが書きました:VisualStudio2010で同様のプログラムを実行してみると、同じ結果が得られました。
static変数は定義された順に静的領域に連続的に格納されるということでしょうか?
C/C++の規格に書かれた事ではありませんので、どうなるかはコンパイラ・リンカを開発したスタッフの趣味と言って良いと思います。
定義順やa,b,c順かも知れませんし、何らかの内部処理の都合(ハッシュ等)で順番が決まるかも知れません。
あと最適化をかけると、この条件は成立しなくなるので同じ動きをしません。リリースビルドをしてみると分かります。
なので、そんな風に思い込むのは危険です。
【補足】
ためにしVC++2008でリリースビルドしたもの。 宿題です。なぜ、こうなるかを推測してみてください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
-
あsdf
Re: static で値を0以外に初期化するとバグが起きます
ためしに、以下の様なプログラムを書いてみました。
これをリリースビルドすると、結果は以下のようになりました。
b[-2]=99
b[-1]=1111
b[0]=3
b[1]=5
b[2]=7
b[3]=0
&b[-2]=011B3018
&b[-1]=011B301C
&b[0]=011B3020
&b[1]=011B3024
&b[2]=011B3028
&b[3]=011B302C
&a = 011B3018 = 99
&c = 011B301C = 1111
*(px)=(011B3024)=5
*(px-2)=(011B301C)=111
*(px+2)=(011B302C)=0
さらに、main内のfunc2をコメントアウトすると、
b[-2]=1
b[-1]=99
b[0]=3
b[1]=5
b[2]=7
b[3]=1
となりました。つまり、リリースビルドをすると、使用していない関数のstatic変数は領域に格納されないということでしょうか?
ただ、値がb[-2]=1のように1になる理由はわかりませんでした。同様に、補足のところに挙げていただいたコードのb[3]=0と0になる理由もわかりませんでした。
(静的領域は、0に初期化されるものだから、b[3]も静的領域に存在し、そのために0となったと思ったのですが、上のようにb[3]=1と1が出てきたしまったためにこれは間違っていると考えました。)
void func(void)
{
static int a = 99;
printf("&a = %p = %d\n", &a, a);
}
void func2(void)
{
static int c = 1111;
printf("&c = %p = %d\n", &c, c);
}
int main()
{
static int b[3] = { 3,5,7 };
int *px = &b[1];
int i;
for( i=-2 ; i<4 ; i++ ) {
printf( "b[%d]=%d\n", i, b[i] );
}
for( i=-2 ; i<4 ; i++ ) {
printf( "&b[%d]=%p\n", i, &b[i] );
}
func();
func2();
printf( "*(px)=(%p)=%d\n", px, *(px) );
printf( "*(px-2)=(%p)=%d\n", px-2, *(px-2) );
printf( "*(px+2)=(%p)=%d\n", px+2, *(px+2) );
}
b[-2]=99
b[-1]=1111
b[0]=3
b[1]=5
b[2]=7
b[3]=0
&b[-2]=011B3018
&b[-1]=011B301C
&b[0]=011B3020
&b[1]=011B3024
&b[2]=011B3028
&b[3]=011B302C
&a = 011B3018 = 99
&c = 011B301C = 1111
*(px)=(011B3024)=5
*(px-2)=(011B301C)=111
*(px+2)=(011B302C)=0
さらに、main内のfunc2をコメントアウトすると、
b[-2]=1
b[-1]=99
b[0]=3
b[1]=5
b[2]=7
b[3]=1
となりました。つまり、リリースビルドをすると、使用していない関数のstatic変数は領域に格納されないということでしょうか?
ただ、値がb[-2]=1のように1になる理由はわかりませんでした。同様に、補足のところに挙げていただいたコードのb[3]=0と0になる理由もわかりませんでした。
(静的領域は、0に初期化されるものだから、b[3]も静的領域に存在し、そのために0となったと思ったのですが、上のようにb[3]=1と1が出てきたしまったためにこれは間違っていると考えました。)
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: static で値を0以外に初期化するとバグが起きます
不要な関数はコンパイラが抹消します。なので実行ファイル中には変数どころかfunc2のプログラムコードも残りません。あsdf さんが書きました:となりました。つまり、リリースビルドをすると、使用していない関数のstatic変数は領域に格納されないということでしょうか?
たまたま、何らかの1に見える値が格納されていたのでしょう。あsdf さんが書きました:ただ、値がb[-2]=1のように1になる理由はわかりませんでした。同様に、補足のところに挙げていただいたコードのb[3]=0と0になる理由もわかりませんでした。
あるいは、標準ライブラリ関数で使われるstatic変数の値かも知れません。
上に書いたのが原因です。自分で書いたものだけでなく標準ライブラリ関数の使う変数も静的領域には含まれています。あsdf さんが書きました:(静的領域は、0に初期化されるものだから、b[3]も静的領域に存在し、そのために0となったと思ったのですが、上のようにb[3]=1と1が出てきたしまったためにこれは間違っていると考えました。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
-
あsdf
Re: static で値を0以外に初期化するとバグが起きます
ありがとうございます。
標準ライブラリ関数でstatic変数を使っているものなんてあるのでしょうか?
例えばどんなものがあるのでしょうか?
標準ライブラリ関数でstatic変数を使っているものなんてあるのでしょうか?
例えばどんなものがあるのでしょうか?
Re: static で値を0以外に初期化するとバグが起きます
例えばstrtokはstatic変数を用いて実装されることが主なのではないかと思います。