【问题标题】:parsing a .conf file in c在 c 中解析 .conf 文件
【发布时间】:2011-12-31 13:21:21
【问题描述】:

也许这座桥可能已经通过很多方式跨越了很多次...阅读一个简单的文本 .conf 文件并根据其条目采取行动。

就我而言,文件格式很简单..一系列标记和赋值,如:

token_name_1    value

使用制表符作为字段分隔符,并为每条记录使用 unix 行尾。

.conf 文件直接更改某些程序配置,所有这些配置都存储在一个结构中。 Integer、float、char[] 和 *char 类型的变量在结构中表示。

一个快速但无聊的方法包括,例如:

if (strcasecmp(token,"token_name_1")==0)
    token_name_1=value;

但我决定在一个很好的紧密循环中做这件事会很甜蜜。在 C 中。

所以似乎最好构造一个数组,它提供指向我希望公开的每个结构变量的指针;另一个提供变量的名称;第三个描述存储的数据类型和所需的默认值。

这些看起来像这样:

const char* allowed_tokens[] =
{
    "loglevel",
    "debugecho",
    "errorSqlDisable",
    "ClearErrorDbOnExit",
    "\0"    // terminates list
}

int *varpointers[] =
{
    &appinfo.nLogLevel,
    &appinfo.debugEcho,
    &appinfo.OWFSLogLevel,
    &appinfo.OWFSLogEchoToDisplay,
    0   // terminates list
};

char *varDatatypes_defaults[] =
{
    "I|6",      // for LOG_INFO
    "B|false",
    "I|0",  
    "B|true",
    "\0"    // terminates list
};

循环看起来像这样(伪代码):

row=0;
while (read a line of the .conf file into cLine)
{
    get the token_name and value from cLine
    check if allowed_tokens[row]==0 and if true, exit the loop
    // example cLine= "debugecho    false"
    find match to "debugecho" in allowed_tokens.  This provides an offset into varpointers and varDatatypes.
    get the default data type and default value tokens from varDattypes_defaults[row]
    Do the assignment.  For example, if the data type=="I":
      *varpointers[row]=atoi(value);

    ++row;
}

这种技术效果很好,但是有两个问题。

  1. 最好将三个数组组合成一个数组。这里有最佳做法吗?
  2. 指针数组 (varpointers[]) 定义为 *int。我这样做是因为我希望它保持指针。但是,如果指向的变量不是整数数据类型,则会触发警告:从不兼容的指针类型初始化。当然,char * 和 int * 是不能混用的……那要怎么做才能使用单个指针数组呢?

我意识到我可以在 c++ 中完成所有这些工作。在这一点上,这种奢侈不是一种选择。

【问题讨论】:

  • 不知道你是否熟悉 YAML (yaml.org),但这可能是进行标准配置解析的更好方法。

标签: c arrays parsing configuration-files variable-assignment


【解决方案1】:
  1. 如果我们讨论的是相同的数据类型,请使用双指针(您会得到一个数组数组)
  2. 声明一个包含指针的结构,然后使用指向您的结构的指针来处理。

要声明一个通用指针,您可以使用 void 代替 int。但是每次你必须转换指针才能正确使用它。

【讨论】:

    【解决方案2】:

    您可以通过结构将它们组合成一个数组,例如

    typedef struct { char *token; void *var; char *defaults; } the_type;
    
    the_type the_data[] = { { "loglevel",  (void*)&appinfo.nLogLevel, "I|6" },
                            { "debugecho", (void*)&appinfo.debugEcho, "B|false" }, 
                          ... 
                          };
    

    通用指针类型是void *。您的代码必须确保在实际写入指向的变量时使用正确的类型,例如*(int*)the_data[0] = 42;.

    【讨论】:

      【解决方案3】:

      我会使用枚举来指定类型,这样您就不必解析字符串。这些值可以存储在联合中。

      typedef enum {
          BOOLEAN,
          INTEGER,
      } type_t;
      
      typedef union value {
          bool boolean;
          int integer;
      } value_t;
      
      typedef struct token {
          char *name;
          type_t type;
          value_t value;
      } token_t;
      

      现在您可以像这样定义默认值:

      token_t data[] = {
          { "loglevel", INTEGER, { 6 } },
          { "debugecho", BOOLEAN, { false } },
          { "errorSqlDisable", INTEGER, { 0 } },
          { "ClearErrorDbOnExit", BOOLEAN, { true } },
          { 0 }
      };
      

      如果配置键的数量很大,这将变得非常麻烦。您可能需要考虑将配置存储在哈希表或树中。

      这是一个简短的example,似乎可以实现您想要的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-02
        • 2014-05-06
        • 1970-01-01
        • 2015-01-29
        相关资源
        最近更新 更多