int* n; *n = 5; がバスエラーにならない方法
某所の記事内に掲載された表題のコードが話題になっている。
私の手元では必ずバスエラーで死んでしまう。おかしいな。
「そんな、Javaの本に記事を書くような人のコードが間違っているわけがないじゃないですか!」
おお!さすがポジティブシンキング!そうです、きっと私のやりかたが何か間違っているんです。
というわけで、意地でも int *n; *n = 5; を通してみたのがこれ。
(全く同じバージョンのコンパイラじゃないとこの動作にならないので注意)
【環境】
gcc --version
i686-apple-darwin9-gcc-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5478)
又は
gcc-4.2 --version
i686-apple-darwin9-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5555)
【コンパイル】
gcc -m64 -O1 hello.c (-m32でも同じだった)
【実行】
./a.out
【結果】
5
【課題】
最適化無し( -O0 ) での動作 - O0だと自動変数の領域が再利用されないみたいなので厳しいかも
他環境への対応 - Linux(x86_64)上の gcc 4.1.2では Segmentation Faultになってしまった。幅広い環境に対応出来る方が良い。
【FAQ】
Q.原理
A.コンパイラに -S をつけてアセンブリ出力させればわかるかも。それで色々試して、「偶然そうなる」方法を探しただけ。
Q.っていうかなんで printfで表示してるのが *nじゃなくて _iなのw
A.代入の時点でバスエラーやSEGVが起こらなければ、そこで*nが 5になることに何ら不思議はなくそれだとつまんないから。
Q.スコープの途中で変数宣言
A.最初は古いCの書法にこだわって書こうと思ったんだけど、今日びのgccじゃ -stdに何を与えてもそれが出来てしまうっぽいのであきらめて使うことにした。
Q._i が初期化されていないんじゃ?
A.そこはゼロクリアされることになってるよ。ISO/IEC 9899:1999>5.1.2 Execution environments>All objects with static storage duration shall be initialized (set totheir initial values) before program startup.
で、真面目な話をすると。
問題のコードがバスエラーにならずに通ってしまうケースがむしろ一番プロジェクトに深刻な打撃を与える。
なにせ「_i には 1を代入したはずなのに、いつのまにか5に置き換わっている」ばかりか、ソースコードをどう追跡したところでポインタ nを用いた間接代入と変数 _iの内容には因果関係など発見できないのだ。
私の手元では必ずバスエラーで死んでしまう。おかしいな。
「そんな、Javaの本に記事を書くような人のコードが間違っているわけがないじゃないですか!」
おお!さすがポジティブシンキング!そうです、きっと私のやりかたが何か間違っているんです。
というわけで、意地でも int *n; *n = 5; を通してみたのがこれ。
(全く同じバージョンのコンパイラじゃないとこの動作にならないので注意)
#include <stdio.h>
int _i;
int main( )
{
int *i;
*(i = &_i+_i) = 1;
/* ここから */
int *n;
*n = 5;
/* ここまで */
printf("%d\n", _i);
return 0;
}
【環境】
gcc --version
i686-apple-darwin9-gcc-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5478)
又は
gcc-4.2 --version
i686-apple-darwin9-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5555)
【コンパイル】
gcc -m64 -O1 hello.c (-m32でも同じだった)
【実行】
./a.out
【結果】
5
【課題】
最適化無し( -O0 ) での動作 - O0だと自動変数の領域が再利用されないみたいなので厳しいかも
他環境への対応 - Linux(x86_64)上の gcc 4.1.2では Segmentation Faultになってしまった。幅広い環境に対応出来る方が良い。
【FAQ】
Q.原理
A.コンパイラに -S をつけてアセンブリ出力させればわかるかも。それで色々試して、「偶然そうなる」方法を探しただけ。
Q.っていうかなんで printfで表示してるのが *nじゃなくて _iなのw
A.代入の時点でバスエラーやSEGVが起こらなければ、そこで*nが 5になることに何ら不思議はなくそれだとつまんないから。
Q.スコープの途中で変数宣言
A.最初は古いCの書法にこだわって書こうと思ったんだけど、今日びのgccじゃ -stdに何を与えてもそれが出来てしまうっぽいのであきらめて使うことにした。
Q._i が初期化されていないんじゃ?
A.そこはゼロクリアされることになってるよ。ISO/IEC 9899:1999>5.1.2 Execution environments>All objects with static storage duration shall be initialized (set totheir initial values) before program startup.
で、真面目な話をすると。
問題のコードがバスエラーにならずに通ってしまうケースがむしろ一番プロジェクトに深刻な打撃を与える。
なにせ「_i には 1を代入したはずなのに、いつのまにか5に置き換わっている」ばかりか、ソースコードをどう追跡したところでポインタ nを用いた間接代入と変数 _iの内容には因果関係など発見できないのだ。
