不確定特異点

広く深く、ところどころ超深く

5 分で書くパラメータ設定ルーチン

C言語でパラメータを設定するルーチンが欲しい、けれども、一時的な利用なので気合いの入ったのは要らない、というか適当でいいから早く動くものを!!という状況が発生したので、5 分で適当なパラメータ設定ルーチンを書いたのがこれ。

パラメータファイルは、

param0 123.456
param1 789

のように、一行内にパラメータと数値が空白で区切られているフォーマットを想定してます。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define KEY_SIZE 256
#define LENGTH(x) (sizeof(x)/sizeof(x[0]))

typedef struct {
    const char *key;
    double val;
} param_t;

param_t param[] = {
    {"param0", 0},
    {"param1", 0},
};

#define PARAM(x) get_param(param, x)

int set_param(FILE *fp, param_t *param)
{
    char key[KEY_SIZE];
    double val;
    int i;

    while (fscanf(fp, "%s %lf", key, &val) != EOF) {
        for (i = 0; param[i].key != NULL; i++) {
            if (strcmp(param[i].key, key) == 0) {
                param[i].val = val;
                break;
            }
        }
        if (param[i].key == NULL) { /* not found */
            fprintf(stderr, "[set_param] Unknown parameter: %s\n", key);
        }
    }
    
    return 1;
}

double get_param(param_t *param, const char *key)
{
    int i;

    for (i = 0; param[i].key != NULL; i++) {
        if (strcmp(param[i].key, key) == 0) {
            return param[i].val;
        }
    }
    
    fprintf(stderr, "[get_param] Unknown parameter: %s\n", key);

    return 0;
}

int main(int argc, char *argv[])
{
    FILE *fp;
    
    if (argc <= 1) {
        fprintf(stderr, "No file specified.\n");
        exit(1);
    }

    fp = fopen(argv[1], "r");
    if (fp == NULL) {
        fprintf(stderr, "File not found: %s", argv[1]);
        exit(1);
    }
    
    set_param(fp, param);

    printf("param0 = %lf\n", PARAM("param0"));
    printf("param1 = %lf\n", PARAM("param1"));    
    
    return 0;
}

ちょっと改良してみる

モジュールとしての I/F をもうちょっと真面目に考えつつ、任意のパラメータもサイズが許す限り登録できるように機能 UP した 20 分バージョン。

param.h

#ifndef PARAM_H
#define PARAM_H

#include <stdio.h>

#define KEY_SIZE 256

typedef struct {
    char key[KEY_SIZE];
    double val;
} param_t;

void read_param(FILE *fp, param_t *param, size_t size);
double get_param(param_t *param, const char *key);

#endif

param.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "param.h"

void read_param(FILE *fp, param_t *param, size_t size)
{
    int i;
    char key[KEY_SIZE];
    double val;

    for (i = 0; i < size; i++) {
        param[i].key[0] = '\0';
        param[i].val = 0;
    }
    
    while (fscanf(fp, "%s %lf", key, &val) != EOF) {
        for (i = 0; param[i].key[0] != '\0'; i++) {
            if (strcmp(param[i].key, key) == 0) {
                param[i].val = val;
                break;
            }
        }
        if (param[i].key[0] == '\0') {    /* parameter not found */
            if (i >= size - 1) {       /* leave one slot for sentinel */
                fprintf(stderr, "Not enough space for parameter\n");
                exit(1);
            }

            strcpy(param[i].key, key);
            param[i].val = val;
        }
    }
}

double get_param(param_t *param, const char *key)
{
    int i;

    for (i = 0; param[i].key[0] != '\0'; i++) {
        if (strcmp(param[i].key, key) == 0) {
            return param[i].val;
        }
    }
    
    fprintf(stderr, "Unknown parameter: %s\n", key);

    return 0;
}

このモジュールを利用する側はこんな感じになります。

#include <stdio.h>
#include <stdlib.h>

#include "param.h"
#define PARAM_SIZE 1024
param_t param[PARAM_SIZE];
#define PARAM(x) get_param(param, x)

int main(int argc, char *argv[])
{
    FILE *fp;
    
    if (argc <= 1) {
        fprintf(stderr, "No file specified.\n");
        exit(1);
    }

    fp = fopen(argv[1], "r");
    if (fp == NULL) {
        fprintf(stderr, "File not found: %s", argv[1]);
        exit(1);
    }
    
    read_param(fp, param, PARAM_SIZE);
    
    printf("param0 = %lf\n", PARAM("param0"));
    printf("param1 = %lf\n", PARAM("param1"));
    
    return 0;
}

このくらいの低機能でもプロトタイピングには十分使えそうです。