Let's start Scheme

2011-01-04

これってOK?

C言語でこんなのって合法?
static int s_value[5] = {1, 2, 3, 4, 5};
struct rec_t {
  int v[1];
};
static struct s_rec_t
{
  rec_t v[1];
} myth = {
  { s_value }
};
用は構造体の初期化だと思うんだけど、rec_tがint*なら合法なのはいいとして、この場合だとどうなるんだろう?
そのまま見ると1個しかない配列に対して5個入れてるから違法臭いけど、ポインタ自体を書き換えるのであれば合法っぽくもある。
実際、
struct string_t
{
   int size;
   char value[1];
};
---
string_t *s = (string_t*)malloc(sizeof(string_t) + sizeof(char)*10);
strcpy(s->value, "abcdefghi");
s->value[10] = '\0';
なんてのは合法なんだよね。
(いや、仕様書を確認したわけじゃないけど、よく見るテクニックだからそう思ってる。実際char[1]をchar*にするとセグるし、当たり前だが)
ただ、この場合だとポインタを書き換えるのではなく、連続したメモリという扱いになるのかな?
最初のケースだと純粋に書き換えてるから、うっかり鼻から悪魔が出てきても文句が言えなさそうな気はするが。
う~ん。

2 comments:

齊藤 said...

myth.v[0].v[0] が s_value のアドレスで初期化されます。
s_value の内容で初期化されることはありません。
ただ、 int* から int への変換が起こっているので、変換結果は未定義のはずです。
値に意味がない初期化ですが、その値を使わない限りは問題ないと思います。
(とは言っても初期化するからにはその値を使うつもりでしょうから、実質的には間違いですね。)

なお、 static struct s_rec_t {rec_t v[1];} myth; は誤りです。
struct を補って static struct s_rec_t {struct rec_t v[1];} myth; とする必要があります。
C++ ではここで struct を省略できますが C では NG です。

kei said...

コメントに今日気づきました。orz

やっぱりNGなんですね。struct hackの延長みたいな感じで使えるかと思ったのですが。

typedefでstruct s_rec_tをs_tに変更したつもりで書いてました(^^;

Post a Comment