読者です 読者をやめる 読者になる 読者になる

共用体で作るポインタリスト

共用体を使ってポインタのコレクションが作れます。ポインタのサイズ(sizeof(struct Struct*)とsizeof(union PtrList*))が同じだからサイズ的にはok。(struct Struct**)の変数を(union PtrList*)にキャストできるのが新鮮でした。フィールド名を通して元の型に戻せます。

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
struct Struct {
 int c;
};
union PtrList {
  union PtrList* next;
  struct Struct* s;
};
struct Struct* state(int c) {
struct Struct* s = malloc(sizeof(struct Struct));
  s->c = c;
  return s;
}
void append(union PtrList* l1, union PtrList* l2) {
  union PtrList* head_ptr = l1;
  while(l1->next)
    l1 = l1->next;
  assert(NULL == l1->next);
  l1->next = l2;
  l1 = head_ptr;
}
union PtrList* ptr_list(struct Struct** s) {
union PtrList* list = (union PtrList*)s;
  assert(list->next == NULL);
  return list;
}
int main(void) { 
 struct Struct *s1, *s2, *s3, *s4;
 s1 = NULL;s2 = NULL;s3 = NULL;s4 = state('a');
 union PtrList *l1, *l2, *l3;
 l1 = ptr_list(&s1);
 l2 = ptr_list(&s2);
 l3 = ptr_list(&s3);
 union PtrList* l4;
 //l4->s = s1;//これだと動かない
 l4 = (union PtrList*)&s4;
 assert('a' == l4->s->c);
 append(l1, l2);
 append(l1, l3); 
 union PtrList* next;
 int i = 0;
 for(; l1; l1 = next) {
   next = l1->next;
   l1->s = s4;
   i++;
 }
 assert(3 == i);
 assert(NULL == l1);
 assert('a' == s1->c);
 assert('a' == s2->c);
 assert('a' == s3->c);
 free(s4);
 return 0;
}