2011|08|
2013|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|05|06|07|08|09|10|11|12|
2016|01|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|

2017-04-24 Linuxカーネルのリスト構造体の仕組みをユーザプログラムで使う [長年日記]

/*
 大規模シミュレータを作る時に、私は、動的メモリのリスト構造体を大量に使う。
 Linuxカーネルにも、この仕組みがあるらしく、ユーザプログラムでも使う方法が
 解説されていた。
 
 http://qiita.com/chromabox/items/ea9720422d7a974f6ce
 
 c言語でリストを使う時に、役に立ちそうだったので、自分のコメントを付けた
 ものを写させて頂いている。
 
 なお、"list.h"は、kobore.net/list.h.htmlに置いてあり。
  
 */
 
/*
  gcc -g list_demo.c -o list_demo
*/
 
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"
 
typedef struct _tag_datas
{
  int number;
  char name[64];
  list_head _list;
}type_line;
 
const char *ndata[]=  {
  "beagle",
  "cupcake",
  "donut",
  "eclair",
  "froyo",
  "gingerbread",
  "honeycomb",
  "icecleam",
  "jellybean",
  "kitkat",
  NULL,
};
 
// 渡されたリストのエントリが最後かどうか調べる
#define list_is_entry_last(pos, head, member)   \
  &pos->member == (head)
 
int main(int argc,char *argv[])
{
  LIST_HEAD(mylist);  // mylist は リスト変数の宣言と初期化
  int nums=1,i;
  type_line *data = NULL;
  type_line *dend = NULL;
  
  // Listへ要素の追加
  for(i=0;ndata[i] != NULL;i++){
    data = (type_line *)malloc(sizeof(type_line));  // インスタンスを生成
    
    INIT_LIST_HEAD(&data->_list);  // 先頭アドレスを指定(というか「決める」)
 
    data->number = nums;           // 構造体にデータを投入
    strcpy(data->name,ndata[i]);   // 同上
 
    nums++;
 
    list_add_tail(&data->_list, &mylist);  // リスト末尾に追加、リスト先頭に追加する場合はlist_add()を使う
  }
 
  // Listを順にたぐる
  list_for_each_entry(data,&mylist,_list){   // "_list"は構造体の一つ、mylistは先頭のアドレス
    printf("%d: %s\n",data->number,data->name);
  }
  
  // Listを順にたぐりつつ、探す (基本的には上記と同じ)
  list_for_each_entry(data,&mylist,_list){
    if(strcmp(data->name,ndata[4]) == 0){  // ndata[4]と同じ文字列なら、引き出す
      printf("found ! %d: %s\n",data->number,data->name);
      break;
    }
  }
  // Listが最後まで来たかどうか
  if(list_is_entry_last(data,&mylist,_list)){
    printf("not found\n");
  }else{
    printf("continue print\n");
    // 探せたらそこから順にたどる
    // list_for_each_entry_continue だと今dataが示しているところの次から
    // list_for_each_entry_from だと今dataが示しているところになります
    list_for_each_entry_continue(data,&mylist,_list){
      printf("%d: %s\n",data->number,data->name);
    }
  }
  
  // 後始末
  list_for_each_entry_safe(data,dend,&mylist,_list){
    list_del(&data->_list);
    free((void *)data);
  }
  
  return 0;
}