配置文件中的ini,json,以及lua实现方式的优劣比较

by Laniakea.White


一 ini做配置

1.0 ini例子

[test1]
key11=val1
key12 = val2

[test2]
key21=val23

 

1.1 实现方式

只使用语言中最基本的字符串分割方式,或者使用语言自带的正则表达式,对配置内容进行分割,然后解析出来.
windows的话,好像有很古老的API,可以支持解析ini配置文件的。

##1.2 优势
1.通用好: 实现所依赖的功能,是语言中最基本的东西,这就意味着,你可以在十分底层的代码中使用,而不需要引入新的库。比如,在嵌入式或者单片机中都是可以使用。

我自己就是拿来做程序引导时的配置解析的。

1.3 劣势

  1. 不容易做复杂的配置:ini这种结构,要做复杂的配置不太容易,通常使用都是很简单的key-value的方式。比如,如果要做二级子节点,就不行了。
  2. 解析麻烦:还是最原始的分割,然后解析
  3. 容易出错:ini配置时的内容是无类型的,具体要解析成什么格式的数据,需要业务层关联,这样子万一配错了,进行类型转换时就容易出问题。

1.4 一个实现

这里给出一个网上别人的实现:https://blog.csdn.net/weixin_34210740/article/details/92897688

confile.h
/**
 * INI配置文件管理函数库
 * Ini file parse functions.
 * By Hoverlees http://www.hoverlees.com me[at]hoverlees.com
 */
#ifndef _HOVERLEES_INI_CONFIG_H
#define _HOVERLEES_INI_CONFIG_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
//#include <unistd.h>
typedef struct _CONFIG_BTREE_NODE{
 char* key;
 void* data;
 struct _CONFIG_BTREE_NODE* left;
 struct _CONFIG_BTREE_NODE* right;
 char mem[2];
}CONFIG_BTREE_NODE;
typedef struct _CONFIG_BTREE{
 int numNodes;
 CONFIG_BTREE_NODE* root;
}CONFIG_BTREE;
typedef CONFIG_BTREE INI_CONFIG;
typedef int (*CONFIG_BTREE_TRAVERSE_CB)(CONFIG_BTREE_NODE* node);
typedef int (*CONFIG_BTREE_SAVE_TRAVERSE_CB)(FILE* fp,CONFIG_BTREE_NODE* node);
/**
 * ini内容解析函数,从字符串解析配置
 * @param str 字符串
 * @param slen 字符串长度,可以为0,如果为0,函数自动计算字符串长度
 * @param isGBK 如果ini文件使用GBK字符集,设置成1,否则设置成0
 * @return 成功返回INI_CONFIG指针,失败返回null
 */
INI_CONFIG* ini_config_create_from_string(unsigned char* str,int slen,int isGBK);
/**
 * ini内容解析函数,从文件解析配置
 * @param filename 配置文件名
 * @param isGBK 如果ini文件使用GBK字符集,设置成1,否则设置成0
 * @return 成功返回INI_CONFIG指针,失败返回null
 */
INI_CONFIG* ini_config_create_from_file(const char* filename,int isGBK);
/**
 * 配置释放函数,释放所占用的内存及数据结构
 * @param config 配置对象指针
 * @return 成功返回1,失败返回0
 */
void ini_config_destroy(INI_CONFIG* config);
/**
 * 获取配置整数值
 * @param config 配置对象指针
 * @param section 段名,没有段名时可以为NULL
 * @param key 键名
 * @param default_int 默认值
 * @return 如果配置中有此键对应的值,返回该值,否则返回参数指定的默认值 
 */
int ini_config_get_int(INI_CONFIG* config,const char* section,const char* key,int default_int);
/**
 * 获取配置字符串值
 * @param config 配置对象指针
 * @param section 段名,没有段名时可以为NULL
 * @param key 键名
 * @param default_string 默认值
 * @return 如果配置中有此键对应的值,返回该值,否则返回参数指定的默认值 
 */
char* ini_config_get_string(INI_CONFIG* config,const char* section,const char* key,char* default_string);
/**
 * 设置变量
 * @param config 配置对象指针
 * @param section 段名,没有段名时可以为NULL
 * @param key 键名
 * @param key_len 键长
 * @param value 值
 * @param value_len 值长度
 * @return 成功为1,失败为0
 */
int ini_config_set_string(INI_CONFIG* config,const char* section,const char* key,int key_len,const char* value,int value_len);
/**
 * 设置变量
 * @param config 配置对象指针
 * @param section 段名,没有段名时可以为NULL
 * @param key 键名
 * @param key_len 键长
 * @param value 整数值
 * @return 成功为1,失败为0
 */
int ini_config_set_int(INI_CONFIG* config,const char* section,const char* key,int key_len,int value);
/**
 * 保存配置到文件中 *提示,原先配置文件中的注释信息将不会保存.
 * @param config 配置对象指针
 * @param filename 保存到的文件
 * @return 成功为1,失败为0
 */
int ini_config_save(INI_CONFIG* config,const char* filename);
/**
 * 类似于ini_config_save,只是参数是文件指针,此函数可以直接使用stdin,stdout,stderr. *提示:本函数不负责关闭fp.
 * @param config 配置对象指针
 * @param fp 文件指针
 * @return 成功为1,失败为0
 */
int ini_config_print(INI_CONFIG* config,FILE* fp);
#endif
confile.c
 
/**
 * INI配置文件管理函数库
 * Ini file parse functions.
 * By Hoverlees http://www.hoverlees.com me[at]hoverlees.com
 */
 
#include "confile.h"
#define MAX_SECTION_SIZE 64
typedef struct _PARSER{
 int status;
 int pos;
 int start1;
 int end1;
 int start2;
 int end2;
 int row;
 int col;
 unsigned char* str;
 int slen;
 INI_CONFIG* config;
 char section_name[MAX_SECTION_SIZE];
}PARSER;
typedef int (*PARSER_JUMP_FUNC)(PARSER* parser);
#define PARSE_STATUS_GET_KEY_OR_SECTION 1
#define PARSE_STATUS_GET_SECTION  2
#define PARSE_STATUS_GET_VALUE   3
#define PARSE_STATUS_COMMENT_LINE  4
CONFIG_BTREE_NODE* config_btree_find_node(CONFIG_BTREE* config,const char* key);
/**
 * 内部使用函数,实现内存段trim,返回第一个非空字符指针及字符串trim后的长度.
 */
char* mem_trim(char* src,int len,int* outlen){
 int start,end;
 if(len==0) return NULL;
 start=0;
 end=len-1;
 while(start<len && (src[start]==' ' || src[start]=='\r' || src[start]=='\n')){
  start++;
 }
 while(end>start && (src[end]==' ' || src[end]=='\r' || src[end]=='\n')){
  end--;
 }
 end=end+1;
 if(start==end) return NULL;
 src+=start;
 *outlen=end-start;
 return src;
}
/**
 * 下面是存储配置专用的二叉树实现.
 */
CONFIG_BTREE_NODE* config_btree_create_node(const char* key,int key_len,void* data,int data_len){
 char* p;
 CONFIG_BTREE_NODE* node;
 if(key_len==0) key_len=strlen(key);
 if(data_len==0) data_len=strlen(data)+1;
 node=(CONFIG_BTREE_NODE*) calloc(sizeof(CONFIG_BTREE_NODE)+key_len+data_len,1);
 if(node!=NULL){
  p=node->mem;
  node->key=p;
  p+=(key_len+1);
  node->data=p;
  memcpy(node->key,key,key_len);
  memcpy(node->data,data,data_len);
  node->left=NULL;
  node->right=NULL;
 }
 return node;
}
int config_btree_free_node(CONFIG_BTREE_NODE* node){
 free(node);
 return 1;
}
CONFIG_BTREE* config_btree_create(){
 CONFIG_BTREE* ret=(CONFIG_BTREE*) calloc(sizeof(CONFIG_BTREE),1);
 return ret;
}
int config_btree_insert_node(CONFIG_BTREE* config,const char* key,int key_len,void* data,int data_len){
 CONFIG_BTREE_NODE *p,**prev;
 CONFIG_BTREE_NODE* node;
 int comp;
 if(key_len==0) key_len=strlen(key);
 node=config_btree_create_node(key,key_len,data,data_len);
 if(node==NULL) return 0;
 p=config->root;
 prev=&config->root;
 if(!p){
  config->root=node;
  config->numNodes++;
  return 1;
 }
 while(p){
  comp=memcmp(key,p->key,key_len);
  if(comp>0){
   if(p->right==NULL){
    p->right=node;
    config->numNodes++;
    return 1;
   }
   prev=&p->right;
   p=p->right;
  }
  else if(comp<0){
   if(p->left==NULL){
    p->left=node;
    config->numNodes++;
    return 1;
   }
   prev=&p->left;
   p=p->left;
  }
  else{
   node->left=p->left;
   node->right=p->right;
   *prev=node;
   config_btree_free_node(p);
   return 2; //update
  }
 }
}
int config_btree_insert_section(CONFIG_BTREE* config,const char* section_name){
 CONFIG_BTREE* section=config_btree_create();
 if(section==NULL) return 0;
 if(config_btree_insert_node(config,section_name,0,&section,sizeof(void*))){
  return 1;
 }
 else{
  free(section);
  return 0;
 }
}
CONFIG_BTREE* config_btree_get_section(CONFIG_BTREE* config,const char* section_name){
 CONFIG_BTREE* section;
 CONFIG_BTREE_NODE* node;
 node=config_btree_find_node(config,section_name);
 if(node==NULL) return NULL;
 memcpy(&section,node->data,sizeof(void*));
 return section;
}
int config_btree_insert_section_node(CONFIG_BTREE* config,const char* section_name,const char* key,
          int key_len,void* data,int data_len){
 CONFIG_BTREE* section;
 CONFIG_BTREE_NODE* node;
 node=config_btree_find_node(config,section_name);
 if(node==NULL) return 0;
 memcpy(&section,node->data,sizeof(void*));
 return config_btree_insert_node(section,key,key_len,data,data_len);
}
CONFIG_BTREE_NODE* config_btree_find_node(CONFIG_BTREE* config,const char* key){
 CONFIG_BTREE_NODE* p;
 int comp;
 p=config->root;
 while(p){
  comp=strcmp(key,p->key);
  if(comp>0){
   p=p->right;
  }
  else if(comp<0){
   p=p->left;
  }
  else{
   return p;
  }
 }
 return NULL;
}
int config_btree_delete_node(CONFIG_BTREE* config,const char* key){
 CONFIG_BTREE_NODE* p;
 CONFIG_BTREE_NODE* temp;
 CONFIG_BTREE_NODE** prevTmpPos=NULL;
 CONFIG_BTREE_NODE** prevPos=NULL;
 int comp;
 prevPos=&config->root;
 p=config->root;
 while(p){
  comp=strcmp(key,p->key);
  if(comp>0){
   prevPos=&p->right;
   p=p->right;
  }
  else if(comp<0){
   prevPos=&p->left;
   p=p->left;
  }
  else{
   if(p->left){
    temp=p->left;
    while(temp->right){
     prevTmpPos=&temp->right;
     temp=temp->right;
    }
    if(prevTmpPos==NULL){
     *prevPos=temp;
     temp->right=p->right;
    }
    else{
     if(temp->left){
      *prevTmpPos=temp->left;
     }
     else{
      *prevTmpPos=NULL;
     }
     *prevPos=temp;
     temp->left=p->left;
     temp->right=p->right;
    }
    config_btree_free_node(p);
   }
   else if(p->right){
    temp=p->right;
    while(temp->left){
     prevTmpPos=&temp->left;
     temp=temp->left;
    }
    if(prevTmpPos==NULL){
     *prevPos=temp;
     temp->left=p->left;
    }
    else{
     if(temp->right){
      *prevTmpPos=temp->right;
     }
     else{
      *prevTmpPos=NULL;
     }
     *prevPos=temp;
     temp->left=p->left;
     temp->right=p->right;
    }
    config_btree_free_node(p);
   }
   else{
    config_btree_free_node(p);
    *prevPos=NULL;
   }
   config->numNodes--;
   return 1;
  }
 }
 return 0;
}
int config_btree_inorder_traverse(CONFIG_BTREE_NODE* node,CONFIG_BTREE_TRAVERSE_CB callback){
 if(node==NULL) return 1;
 if(!config_btree_inorder_traverse(node->left,callback)) return 0;
 if(!callback(node)) return 0;
 if(!config_btree_inorder_traverse(node->right,callback)) return 0;
 return 1;
}
int config_btree_inorder_save_traverse(CONFIG_BTREE_NODE* node,FILE* fp,CONFIG_BTREE_SAVE_TRAVERSE_CB callback){
 if(node==NULL) return 1;
 if(!config_btree_inorder_save_traverse(node->left,fp,callback)) return 0;
 if(!callback(fp,node)) return 0;
 if(!config_btree_inorder_save_traverse(node->right,fp,callback)) return 0;
 return 1;
}
int config_btree_preorder_traverse(CONFIG_BTREE_NODE* node,CONFIG_BTREE_TRAVERSE_CB callback){
 if(node==NULL) return 1;
 if(!callback(node)) return 0;
 if(!config_btree_preorder_traverse(node->left,callback)) return 0;
 if(!config_btree_preorder_traverse(node->right,callback)) return 0;
 return 1;
}
int config_btree_postorder_traverse(CONFIG_BTREE_NODE* node,CONFIG_BTREE_TRAVERSE_CB callback){
 if(node==NULL) return 1;
 if(!config_btree_postorder_traverse(node->left,callback)) return 0;
 if(!config_btree_postorder_traverse(node->right,callback)) return 0;
 if(!callback(node)) return 0;
 return 1;
}
int config_btree_destroy_section(CONFIG_BTREE_NODE* node){
 CONFIG_BTREE* section;
 if(!node) return 0;
 memcpy(&section,node->data,sizeof(void*));
 config_btree_postorder_traverse(section->root,config_btree_free_node);
 free(section);
}
int config_btree_destroy(CONFIG_BTREE* config){
 if(!config) return 0;
 config_btree_postorder_traverse(config->root,config_btree_destroy_section);
 free(config);
 return 1;
}
/**
 * ini文件解析函数跳转表,此方式在大型解析的实现中非常高效.
 */
int parser_default_action(PARSER* parser){
 parser->pos++;
 parser->col++;
 return 1;
}
int parse_default_gbk_action(PARSER* parser){
 parser->pos+=2;
 parser->col+=2;
 return 1;
}
int parser_on_section_start(PARSER* parser){
 if(parser->status==PARSE_STATUS_COMMENT_LINE){}
 else if(parser->status==PARSE_STATUS_GET_KEY_OR_SECTION){
  parser->start1=parser->pos+1;
  parser->status=PARSE_STATUS_GET_SECTION;
 }
 parser->pos++;
 parser->col++;
 return 1;
}
int parser_on_section_end(PARSER* parser){
 char* p;
 int len,r;
 if(parser->status==PARSE_STATUS_COMMENT_LINE){}
 else if(parser->status==PARSE_STATUS_GET_SECTION){
  memset(parser->section_name,0,MAX_SECTION_SIZE);
  p=mem_trim(parser->str+parser->start1,parser->pos-parser->start1,&len);
  if(p==NULL){//section段名不能为空
   return 0;
  }
  memcpy(parser->section_name,p,len);
  r=config_btree_insert_section(parser->config,parser->section_name);
  if(r==0) return 0;//添加section失败
  parser->status=PARSE_STATUS_GET_KEY_OR_SECTION;
  parser->start1=parser->pos+1;
 }
 parser->pos++;
 parser->col++;
 return 1;
}
int parser_on_value_start(PARSER* parser){
 char* p;
 int len,r;
 if(parser->status==PARSE_STATUS_GET_KEY_OR_SECTION){
  parser->status=PARSE_STATUS_GET_VALUE;
  parser->end1=parser->pos;
  parser->start2=parser->pos+1;
 }
 parser->pos++;
 parser->col++;
 return 1;
}
int parser_on_new_line(PARSER* parser){
 char *k,*v;
 int klen,vlen;
 switch(parser->status){
  case PARSE_STATUS_COMMENT_LINE:
   break;
  case PARSE_STATUS_GET_VALUE:
   k=mem_trim(parser->str+parser->start1,parser->end1-parser->start1,&klen);
   v=mem_trim(parser->str+parser->start2,parser->pos-parser->start2,&vlen);
   if(k==NULL) return 0;
   if(v==NULL){
    v="";
    vlen=0;
   }
   if(!config_btree_insert_section_node(parser->config,parser->section_name,k,klen,v,vlen)) return 0;
   break;
  case PARSE_STATUS_GET_KEY_OR_SECTION:
   break;
  default:
   return 0;
 }
 parser->start1=parser->pos+1;
 parser->status=PARSE_STATUS_GET_KEY_OR_SECTION;
 parser->pos++;
 parser->col=1;
 parser->row++;
 return 1;
}
int parser_on_comment(PARSER* parser){
 if(parser->col==1){
  parser->status=PARSE_STATUS_COMMENT_LINE;
 }
 parser->col++;
 parser->pos++;
 return 1;
}
/**
 * 接下来是ini配置管理的上层函数.
 */
INI_CONFIG* ini_config_create_from_string(unsigned char* str,int slen,int isGBK){
 int r;
 PARSER parser;
 PARSER_JUMP_FUNC funcs[256];
 INI_CONFIG* config=config_btree_create();
 if(slen==0) slen=strlen(str);
 strcpy(parser.section_name,"default");
 parser.pos=0;
 parser.status=PARSE_STATUS_GET_KEY_OR_SECTION;
 parser.start1=0;
 parser.str=str;
 parser.slen=slen;
 parser.row=1;
 parser.col=1;
 parser.config=config;
 //初始化解析跳转表
 if(isGBK){
  for(r=0;r<127;r++){
   funcs[r]=parser_default_action;
  }
  for(r=128;r<256;r++){
   funcs[r]=parse_default_gbk_action;
  }
 }
 else{
  for(r=0;r<256;r++){
   funcs[r]=parser_default_action;
  }
 }
 funcs['[']=parser_on_section_start;
 funcs[']']=parser_on_section_end;
 funcs['=']=parser_on_value_start;
 funcs['\n']=parser_on_new_line;
 funcs[';']=parser_on_comment;
 
 if(config!=NULL){
  r=config_btree_insert_section(config,parser.section_name);
  if(!r){
   config_btree_destroy(config);
   return NULL;
  }
 }
 while(parser.pos<slen){
  r=funcs[str[parser.pos]](&parser);
  if(!r){ //解析错误,本代码不做任何提示,直接返回NULL,但可以从parser里在这里从parser里取得当前解析的文件位置和当前状态.
   config_btree_destroy(config);
   return NULL;
  }
 }
 r=parser_on_new_line(&parser); if(!r){ 
  config_btree_destroy(config);
  return NULL;
 }
 return config;
}
INI_CONFIG* ini_config_create_from_file(const char* filename,int isGBK){
 FILE* file;
 INI_CONFIG* config;
 char* buf;
 struct stat s;
 if(stat(filename,&s)) return NULL;
 buf=malloc(s.st_size);
 if(buf==NULL) return NULL;
 file=fopen(filename,"r");
 if(file==NULL){
  free(buf);
  return NULL;
 }
 fread(buf,s.st_size,1,file);
 config=ini_config_create_from_string(buf,s.st_size,isGBK);
 free(buf);
 return config;
}
void ini_config_destroy(INI_CONFIG* config){
 config_btree_destroy(config);
}
int ini_config_get_int(INI_CONFIG* config,const char* section,const char* key,int default_int){
 CONFIG_BTREE_NODE* node;
 INI_CONFIG* sec;
 if(section==NULL) section="default";
 sec=config_btree_get_section(config,section);
 if(sec==NULL) return default_int;
 node=config_btree_find_node(sec,key);
 if(node==NULL) return default_int;
 return atoi(node->data);
}
char* ini_config_get_string(INI_CONFIG* config,const char* section,const char* key,char* default_string){
 CONFIG_BTREE_NODE* node;
 INI_CONFIG* sec;
 if(section==NULL) section="default";
 sec=config_btree_get_section(config,section);
 if(sec==NULL) return default_string;
 node=config_btree_find_node(sec,key);
 if(node==NULL) return default_string;
 return (char*)node->data;
}
int ini_config_set_string(INI_CONFIG* config,const char* section,const char* key,int key_len,const char* value,int value_len){
 CONFIG_BTREE* sect;
 CONFIG_BTREE* node;
 int r;
 if(section==NULL) section="default";
 sect=config_btree_get_section(config,section);
 if(sect==NULL){
  r=config_btree_insert_section(config,section);
  if(!r) return 0;
  sect=config_btree_get_section(config,section);
 }
 return config_btree_insert_node(sect,key,key_len,(void*)value,value_len);
}
int ini_config_set_int(INI_CONFIG* config,const char* section,const char* key,int key_len,int value){
 char number[32];
 int len=sprintf(number,"%d",value);
 return ini_config_set_string(config,section,key,key_len,number,len);
}
int ini_config_save_traverse_value(FILE* fp,CONFIG_BTREE_NODE* node){
 fprintf(fp,"%s=%s\n",node->key,(char*)node->data);
 return 1;
}
int ini_config_save_traverse_section(FILE* fp,CONFIG_BTREE_NODE* node){
 CONFIG_BTREE* section;
 memcpy(&section,node->data,sizeof(void*));
 fprintf(fp,"[%s]\n",node->key);
 config_btree_inorder_save_traverse(section->root,fp,ini_config_save_traverse_value);
 return 1;
}
int ini_config_save(INI_CONFIG* config,const char* filename){
 FILE* fp=fopen(filename,"w");
 if(fp==NULL) return 0;
 config_btree_inorder_save_traverse(config->root,fp,ini_config_save_traverse_section);
 fclose(fp);
 return 1;
}
int ini_config_print(INI_CONFIG* config,FILE* fp){
 if(fp==NULL) return 0;
 config_btree_inorder_save_traverse(config->root,fp,ini_config_save_traverse_section);
 return 1;
}

二 json 做配置

2.0 介绍

这个不用多介绍了。铺天盖地的使用。
json不单用于配置文件的实现,也可以用于数据的传递

2.1 劣势

  1. 加注释不方便,即使我们用一个额外的字段来存储注释,也会被解析
  2. 解析和配置文件的结构强相关:如果Json的树形结构发生变化,解析实现也要跟着改,
    即使实现一个可以解析无限深度json树的解析,但是业务层的更改也是很麻烦。
  3. 业务层使用有点复杂:如果是简单的配置很好用。如果json树的深度很深,业务层需要一个个节点的找下去。

业务中,我是用用milo的rapidjson,做简单的包装后使用


三 lua做配置文件

3.0 介绍

使用lua的table来做配置文件的数据存储,然后使用Lua原生的方式来遍历table.

3.1 优势

  1. 天生支持树形结构。

  2. 支持各种各样的key:可以是数字的key,也可以是string的key,甚至可以是对象key.

  3. 容易跨语言支持:lua可以直接使用,如果是其他语言,做一下lua接口的bind实现,就可以使用。

  4. 使用简单:比如我们想访问深层节点,业务层直接使用Get(‘root->node1->node12->node123’)这样子就可以获取到深层节点的内容

  5. 跟业务层弱关联:可以跟业务层无关联,解析是一个通用的解析,不同项目的业务,不需要根据业务重新实现一次解析,直接使用同一份解析,就可以直接使用。

  6. 功能强大:lua本身就是一门语言,可以提供很多功能,比如配置文件的错误检测,配置数据的数据注释等等。

  7. 跨平台:lua是基于 ANSC C实现的,几乎可以在所有平台上使用。本人就在嵌入式,单片机上使用过

  8. 十分动态:数据是可以直接写死在table,也可以是指向一个函数运行的结果,这样意味着,我们可以将配置数据跟一段逻辑相关联。比如,config={version=get_cur_version()}就表示了version这个字段可以根据get_cur_version来确定。甚至,我们可以将version指向网络请求返回的数据。你能想象,配置文件里面可以支持网络连接!!!!

3.2 劣势

  1. 需要学习一下lua。
  2. 怎么防止配置文件被注入破坏性代码,导致问题。因为lua的配置文件也是lua代码文件,里面可以放置可执行代码,如果被恶意放入代码,也被执行了,这个很大问题。

3.3 一个实现

3.3.1 lua的解析实现

lua解析的实现

--[[
 ]]

package.path = package.path ..';/home/config/?.lua;';
---------------------------------------------------------------------------------------------------------------------------------
--[[
	if  another config file use, change the require
]]
function get_config_file()
	local config = require('config');
	return config;
end
---------------------------------------------------------------------------------------------------------------------------------
--[[
]]
function  GetRootInt(key)
 
	local config = get_config_file();
	local INVALID_VAL = -99999999;
	for k,v in pairs(config) do
		if k == key then
			--print(v);
			return v;
		end
	end
	return INVALID_VAL;

end

--[[


]]
function  GetRootString(key)
 
	local config = get_config_file();
 
	for k,v in pairs(config) do
		if k == key then
			return v;
		end
	end
	return '';
end


--[[
	get int array
]]
 
function  GetRootIntArray(key)
	DATA_CACHE.CleanCache();
	local config =  get_config_file();
 
	for k,v in pairs(config) do
		if k == key then

			GetArrayIntData(v);
			return;
		end
	end
end



--[[
	get double array
]]
function  GetRootDoubleArray(key)
	DATA_CACHE.CleanCache();
	local config =  get_config_file();
 
	for k,v in pairs(config) do
		if k == key then

			GetArrayDoubleData(v);
			return;
		end
	end
end


--[[
	get string  array
]]
function  GetRootStringArray(key)
	DATA_CACHE.CleanCache();
	local config = get_config_file();
 
	for k,v in pairs(config) do
		if k == key then

			GetArrayStringData(v);
			return;
		end
	end
end

--------------------------------------------------------------------------------------------------------------------------------------------------------------------
--[[
]]
function  GetChildInt(path,key)
	local ret = get_child_val(path,key,-99999999);
	if nil == ret then
		return -99999999;
	else
		return ret;
	end 
end

function  GetChildDouble(path,key)
	local ret = get_child_val(path,key,-99999999);
	if nil == ret then
		return -99999999;
	else
		return ret;
	end 
end


--[[

]]
function  GetChildString(path,key)
	local ret = get_child_val(path,key,'');
	if nil == ret then
		return '';
	else
		return ret;
	end 
end


--[[

]]
function  GetChildIntArray(path,key)
	DATA_CACHE.CleanCache();
	local split_key = '-';
	local path_list = str_split(path,split_key);
	local path_size = #path_list;
	--[[
			child node should at lease have 2 path, one for root,one for child node
		]]
	if 1 >= path_size then
		return;
	end

	local config = get_config_file();

	--first node is root,remove it
	table.remove(path_list,1);

	local right_node = get_right_node(path_list,config);
	if nil == right_node then
		return;
	end

	--TODO: should check right_node is table
	for k,v in pairs(right_node) do
		if k == key then
			GetArrayIntData(v);
			return;
		end
	end
 
end


--[[

]]
function  GetChildDoubleArray(path,key)
	DATA_CACHE.CleanCache();
	local split_key = '-';
	local path_list = str_split(path,split_key);
	local path_size = #path_list;
	--[[
			child node should at lease have 2 path, one for root,one for child node
		]]
	if 1 >= path_size then
		return;
	end

	local config = get_config_file();

	--first node is root,remove it
	table.remove(path_list,1);

	local right_node = get_right_node(path_list,config);
	if nil == right_node then
		return;
	end

	--TODO: should check right_node is table
	for k,v in pairs(right_node) do
		if k == key then
			GetArrayDoubleData(v);
			return;
		end
	end
 
end

--[[

]]
function  GetChildStringArray(path,key)
	DATA_CACHE.CleanCache();
	local split_key = '-';
	local path_list = str_split(path,split_key);
	local path_size = #path_list;
	--[[
			child node should at lease have 2 path, one for root,one for child node
		]]
	if 1 >= path_size then
		return;
	end

	local config = get_config_file();

	--first node is root,remove it
	table.remove(path_list,1);

	local right_node = get_right_node(path_list,config);
	if nil == right_node then
		return;
	end

	--TODO: should check right_node is table
	for k,v in pairs(right_node) do
		if k == key then
			GetArrayStringData(v);
			return;
		end
	end
 
end

--[[
	internal use
]]
function  get_child_val(path,key,INVALID_VAL)
	local split_key = '-';
	local path_list = str_split(path,split_key);
	local path_size = #path_list;
	--[[
			child node should at lease have 2 path, one for root,one for child node
		]]
	if 1 >= path_size then
		return INVALID_VAL-1;
	end

	local config = get_config_file();

	--first node is root,remove it
	table.remove(path_list,1);

	local right_node = get_right_node(path_list,config);
	if nil == right_node then
		return INVALID_VAL -2;
	end
	return right_node[key];
end
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
--[[
	find the deepest child node
]]
function get_right_node(path_list,config)
	local cur_child_node_name = path_list[1];
	for k,v in pairs(config) do
		if k == cur_child_node_name then
			--find the node
			if 1 == #path_list then
				--final_node
				return v;
			else
				--go deeper node
				table.remove(path_list,1);
				return get_right_node(path_list,v);
			end
		end
	end
	return nil;
end


--[[


]]
function str_split(str,reps)
    local resultStrList = {}
    string.gsub(str,'[^'..reps..']+',function (w)
        table.insert(resultStrList,w)
    end)
    return resultStrList
end

--[[
	by default,if we don't set index by hand,the index  start with 1,and inc one by one,so we can get the value in declare sort,so can use ipairs
]]
function GetArrayIntData(list)
	for k,v in ipairs(list) do
		print(v);
		DATA_CACHE.AddArrayIntElement(v);
	end
end

--[[
	by default,if we don't set index by hand,the index  start with 1,and inc one by one,so we can get the value in declare sort,so can use [ipairs]
]]
function GetArrayDoubleData(list)
	for k,v in ipairs(list) do
		print(v);
		DATA_CACHE.AddArrayDoubleElement(v);
	end
end

--[[
	by default,if we don't set index by hand,the index  start with 1,and inc one by one,so we can get the value in declare sort,so can use [ipairs]
]]
function GetArrayStringData(list)
	for k,v in ipairs(list) do
		print(v);
		DATA_CACHE.AddArrayStringElement(v);
	end
end


 
 

3.3.2 因为lua返回数值给其他语言不是很方便,所以我做了一个简单的c++bind,用于支持数组

c++提供给lua接口使用的缓存接口LuaCacheInterface.h

#ifndef LUACACHEINTERFACE_H
#define LUACACHEINTERFACE_H

//extern "C"
//{
//#include "lua.h"
//#include "lauxlib.h"
//#include "lualib.h"
//}

#include <string>

typedef struct lua_State lua_State;
typedef int (*lua_CFunction)(lua_State *L);

struct ieo_lua_reg_t
{
    const char *name ;
    lua_CFunction func;
};

#define IEO_LUA_FUNC_INIT(p) { #p, (lua_CFunction)p }

class LuaCacheInterface
{
public:
    LuaCacheInterface();
public:
    virtual int RegistLib(const char *libname, ieo_lua_reg_t *reglist) = 0;
    virtual void CleanAll() = 0;
    virtual int AddIntArrayElement(int val) = 0;
    virtual int AddDoubleArrayElement(double val) = 0;
    virtual int AddStringArrayElement(std::string &val) = 0;
};

#endif // LUACACHEINTERFACE_H

提供给lua使用的API定义:LuaCacheFunction.h

#ifndef LUACACHEFUNCTION_H
#define LUACACHEFUNCTION_H


class LuaCacheInterface;

bool RegisterCacheFunc(LuaCacheInterface *obj);


#endif // LUACACHEFUNCTION_H

LuaCacheFunction.cpp

 #include "LuaCacheFunction.h"
#include "LuaCacheInterface.h"
#include "GlobalKey.h"
#include <iostream>
#include <vector>
using namespace std;

extern "C"
{
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}


namespace IEO_LUA_CACHE_INTERFACE {

typedef std::vector<ieo_lua_reg_t> IEO_FUNC_INFO;

static int CleanCache(lua_State *L)
{
    //get the cache ptr
    // void *key_addr = (void *) &lua_cache_key;
//    lua_pushlightuserdata(L, GLOBAL_KEY::GetKeyAddr());
//    lua_gettable(L, LUA_REGISTRYINDEX);
//    void *ptr = lua_touserdata(L, -1);


    lua_getfield(L, LUA_REGISTRYINDEX, GLOBAL_KEY::CACHE_LUA_KEY);
    void *ptr = lua_touserdata(L, -1);
    LuaCacheInterface *obj = (LuaCacheInterface *) ptr;
    obj->CleanAll();
    return 0;

}

/**
 * @brief AddArrayIntElement
 * @param L
 * @return
 */
static int AddArrayIntElement(lua_State *L)
{
    int val = lua_tonumber(L, 1);

    lua_getfield(L, LUA_REGISTRYINDEX, GLOBAL_KEY::CACHE_LUA_KEY);
    void *ptr = lua_touserdata(L, -1);
    LuaCacheInterface *obj = (LuaCacheInterface *) ptr;
    obj->AddIntArrayElement(val);
    cout << "add int:" << val << endl;
    cout << flush;
    return 0;
}

static int AddArrayDoubleElement(lua_State *L)
{
    double val = lua_tonumber(L, 1);

    lua_getfield(L, LUA_REGISTRYINDEX, GLOBAL_KEY::CACHE_LUA_KEY);
    void *ptr = lua_touserdata(L, -1);
    LuaCacheInterface *obj = (LuaCacheInterface *) ptr;
    obj->AddDoubleArrayElement(val);
    cout << "add double:" << val << endl;
    cout << flush;
    return 0;
}


static int AddArrayStringElement(lua_State *L)
{
    std::string val = std::string(lua_tostring(L, 1));

    lua_getfield(L, LUA_REGISTRYINDEX, GLOBAL_KEY::CACHE_LUA_KEY);
    void *ptr = lua_touserdata(L, -1);
    LuaCacheInterface *obj = (LuaCacheInterface *) ptr;
    obj->AddStringArrayElement(val);
    return 0;
}

/*
 * 由vector转换成数组
 */
static ieo_lua_reg_t *to_func_list(IEO_FUNC_INFO &tmp_list)
{
    ieo_lua_reg_t *tmp_ptr;

    int size = tmp_list.size();
    tmp_ptr = new ieo_lua_reg_t[size + 1];

    for (int i = 0; i < size; ++i)
    {
//      Msg("rigister function[%s]\n", tmp_list.at(i).name);
        tmp_ptr[i] = tmp_list.at(i);
    }
    tmp_ptr[size] = {NULL, NULL}; //要已NULL结尾,不然不同平台可能会有问题

    return tmp_ptr;
}


static ieo_lua_reg_t func_list[] =
{
    IEO_LUA_FUNC_INIT(CleanCache),
    IEO_LUA_FUNC_INIT(AddArrayIntElement),
    IEO_LUA_FUNC_INIT(AddArrayDoubleElement),
    IEO_LUA_FUNC_INIT(AddArrayStringElement),


    {0, 0}
};
}


bool RegisterCacheFunc(LuaCacheInterface *obj)
{
    IEO_LUA_CACHE_INTERFACE::IEO_FUNC_INFO tmp_list;
    ieo_lua_reg_t *tmp = IEO_LUA_CACHE_INTERFACE::func_list;
    for (; tmp->name; ++tmp)
    {
        tmp_list.push_back(*tmp);
    }
    ieo_lua_reg_t *func_list = IEO_LUA_CACHE_INTERFACE::to_func_list(tmp_list);
    obj->RegistLib("DATA_CACHE", func_list);
    return false;
}

c++中获取配置数据的实现 ConfigFileUtil.h

/**
 *
 * @brief  use lua as load config file tools
 *
 *added by xsq,2022-09-01
 */
#ifndef CONFIGFILEUTIL_H
#define CONFIGFILEUTIL_H

#include <string>
#include <vector>
#include "LuaCacheInterface.h"

extern "C"
{
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}


class ConfigFileUtil : public LuaCacheInterface
{
public:
    const int INVALID_VAL = -99999999;
public:
    ConfigFileUtil();
    virtual ~ ConfigFileUtil();

public:
    //-------------------------------------------------
    //root node
    int GetInt(std::string &key);
    std::string GetString(std::string &key);
    int GetIntArray(std::vector<int> &buf, std::string &key);
    int GetDoubleArray(std::vector<double> &buf, std::string &key);
    int GetStringArray(std::vector<std::string> &buf, std::string &key);

    //child node
    int GetChildInt(std::string &path, std::string &key);
    double GetChildDouble(std::string &path, std::string &key);
    std::string GetChildString(std::string &path, std::string &key);
    int GetChildIntArray(std::vector<int> &buf, std::string &path, std::string &key);
    int GetChildDoubleArray(std::vector<double> &buf, std::string &path, std::string &key);
    int GetChildStringArray(std::vector<std::string> &buf, std::string &path, std::string &key);
    //-------------------------------------------------

public:
    int Init(std::string &file_name);
    bool IsError() {return m_bErrorOccur;}
    std::string GetDesc() {return m_desc;}
    void Close();

public:
    //------------------------------------------------------------------------------------
    //LuaCacheInterface   interface
    //for lua use ,do not call by hand
    virtual int RegistLib(const char *libname, ieo_lua_reg_t *reglist);
    virtual void CleanAll();

    virtual int AddIntArrayElement(int val);
    virtual int AddDoubleArrayElement(double val);
    virtual int AddStringArrayElement(std::string &val);
    //------------------------------------------------------------------------------------


private:
    void load_lua_libs();
    void fatal_error_occur();
    void warning_error_occur();
private:
    bool m_bLoaded;
    bool m_bErrorOccur;
    std::string m_desc;
    lua_State *m_state;

private:
    std::vector<int> m_int_array;
    std::vector<double> m_double_array;
    std::vector<std::string> m_str_array;


};

#endif // CONFIGFILEUTIL_H



ConfigFileUtil.cpp

#include "ConfigFileUtil.h"
#include "LuaCacheFunction.h"
#include "GlobalKey.h"
#include <iostream>
using namespace std;


ConfigFileUtil::ConfigFileUtil()
{
    m_state = NULL;
    m_bLoaded = false;
}


ConfigFileUtil::~ConfigFileUtil()
{
    Close();
}

int ConfigFileUtil::RegistLib(const char *libname, ieo_lua_reg_t *reglist)
{
    luaL_openlib(m_state, libname, (luaL_reg *) reglist, 0);

    //----------------------------------------------------------------
//    lua_State *L = m_state;
//    lua_pushlightuserdata(L, (void *) &GLOBAL_KEY::CACHE_LUA_KEY1) ; /**取静态变量i的地址作为key压栈**/
//    lua_pushlightuserdata(L, this);   /**把值压栈**/
//    lua_settable(L, LUA_REGISTRYINDEX); /** &i, value出栈;并且实现register[&i] = value**/

    //----------------------------------------------------------------
    lua_pushlightuserdata(m_state, this);
    lua_setfield(m_state, LUA_REGISTRYINDEX, GLOBAL_KEY::CACHE_LUA_KEY);
    //----------------------------------------------------------------


    //    lua_State *L = m_state;
    //    static int i = 0;

    //    lua_pushlightuserdata(L, (void *) &GLOBAL_KEY::CACHE_LUA_KEY1) ; /**取静态变量i的地址作为key压栈**/

    //    lua_pushlightuserdata(L, this);   /**把值压栈**/
    //    lua_settable(L, LUA_REGISTRYINDEX); /** &i, value出栈;并且实现register[&i] = value**/



    //    lua_pushlightuserdata(L, (void *) & GLOBAL_KEY::CACHE_LUA_KEY1) ; /**取静态变量i的地址作为key压栈**/
    //    lua_gettable(L, LUA_REGISTRYINDEX); /**获取value值,如果函数调用成功,那么value目前在栈顶**/

    //    void *ptr1 = lua_touserdata(L, -1);
    //    LuaCacheInterface *ptr = (LuaCacheInterface *)ptr1;
    //    return 0;
    return 0;
}

void ConfigFileUtil::CleanAll()
{
    m_int_array.clear();
    m_double_array.clear();
    m_str_array.clear();
}

int ConfigFileUtil::AddIntArrayElement(int val)
{
    m_int_array.push_back(val);
    return 0;
}


int ConfigFileUtil::AddDoubleArrayElement(double val)
{
    m_double_array.push_back(val);
    return 0;
}

int ConfigFileUtil::AddStringArrayElement(std::string &val)
{
    m_str_array.push_back(val);
    return 0;
}

int ConfigFileUtil::Init(std::string &file_name)
{
    if (true == m_bLoaded)
    {
        //because of Register lib,can't Init twice
        return 0;
    }

    load_lua_libs();

    int ret = luaL_loadfile(m_state, file_name.data());

    if (0 != ret)
    {
        //load file fail
        return ret;
    }
    ret = lua_pcall(m_state, 0, 0, 0);
    if (0 != ret)
    {
        //load file fail
        return ret;
    }

    m_bLoaded = true;
    m_bErrorOccur = false;
    RegisterCacheFunc(this);

    //pre alloc
    int pre_alloc_size = 100;
    m_int_array.reserve(pre_alloc_size);
    m_double_array.reserve(pre_alloc_size);
    m_str_array.reserve(pre_alloc_size);

    return 0;
}


void ConfigFileUtil::Close()
{
    if (NULL != m_state)
    {
        lua_close(m_state);
        m_state = NULL;
    }
}

int ConfigFileUtil::GetInt(std::string &key)
{
    if (false == m_bLoaded)
    {
        return INVALID_VAL;
    }

    lua_getglobal(m_state, "GetRootInt");
    lua_pushstring(m_state, key.data());
    int ret = lua_pcall(m_state, 1, 1, 0);

    if (0 == ret)
    {
        //no error
        int val = static_cast<int>(lua_tonumber(m_state, -1));
        return val;
    }
    else
    {
        fatal_error_occur();
        return INVALID_VAL;
    }
}

std::string ConfigFileUtil::GetString(std::string &key)
{
    if (false == m_bLoaded)
    {
        return std::string("");
    }

    lua_getglobal(m_state, "GetRootInt");
    lua_pushstring(m_state, key.data());
    int ret = lua_pcall(m_state, 1, 1, 0);

    if (0 == ret)
    {
        //no error
        std::string val =  std::string(lua_tostring(m_state, -1));
        return val;
    }
    else
    {
        fatal_error_occur();
        return std::string("");
    }
}

int ConfigFileUtil::GetIntArray(std::vector<int> &buf, std::string &key)
{
    if (false == m_bLoaded)
    {
        return -1;
    }

    lua_getglobal(m_state, "GetRootIntArray");
    lua_pushstring(m_state, key.data());
    int ret = lua_pcall(m_state, 1, 0, 0);

    if (0 == ret)
    {
        //no error
        cout << "GetIntArray not error" << endl << flush;
        buf.clear();
        for (int i = 0; i < m_int_array.size(); ++i)
        {
            buf.push_back(m_int_array[i]);
        }
    }
    else
    {
        cout << "GetIntArray error" << endl << flush;
        fatal_error_occur();
        return -2;
    }
    return 0;


    //----------------------------------------
//    lua_State *L = m_state;
//    lua_pushlightuserdata(L, (void *) &GLOBAL_KEY::CACHE_LUA_KEY1) ; /**取静态变量i的地址作为key压栈**/
//    lua_pushlightuserdata(L, this);   /**把值压栈**/
//    lua_settable(L, LUA_REGISTRYINDEX); /** &i, value出栈;并且实现register[&i] = value**/

//    lua_pushlightuserdata(L, (void *) & GLOBAL_KEY::CACHE_LUA_KEY1) ; /**取静态变量i的地址作为key压栈**/
//    lua_gettable(L, LUA_REGISTRYINDEX); /**获取value值,如果函数调用成功,那么value目前在栈顶**/

//    void *ptr1 = lua_touserdata(L, -1);
//    LuaCacheInterface *ptr = (LuaCacheInterface *)ptr1;
    //  return 0;
}


int ConfigFileUtil::GetDoubleArray(std::vector<double> &buf, std::string &key)
{
    if (false == m_bLoaded)
    {
        return -1;
    }

    lua_getglobal(m_state, "GetRootDoubleArray");
    lua_pushstring(m_state, key.data());
    int ret = lua_pcall(m_state, 1, 0, 0);

    if (0 == ret)
    {
        //no error
        cout << "GetDoubleArray not error" << endl << flush;
        buf.clear();
        for (int i = 0; i < m_double_array.size(); ++i)
        {
            buf.push_back(m_double_array[i]);
        }
    }
    else
    {
        cout << "GetDoubleArray error" << endl << flush;
        fatal_error_occur();
        return -2;
    }
    return 0;
}

int ConfigFileUtil::GetStringArray(std::vector<std::string> &buf, std::string &key)
{
    if (false == m_bLoaded)
    {
        return -1;
    }

    lua_getglobal(m_state, "GetRootStringArray");
    lua_pushstring(m_state, key.data());
    int ret = lua_pcall(m_state, 1, 0, 0);

    if (0 == ret)
    {
        //no error
        cout << "GetRootStringArray not error" << endl << flush;
        buf.clear();
        for (int i = 0; i < m_str_array.size(); ++i)
        {
            buf.push_back(m_str_array[i]);
        }
    }
    else
    {
        cout << "GetRootStringArray error" << endl << flush;
        fatal_error_occur();
        return -2;
    }
    return 0;
}

/**
 * @brief ConfigFileUtil::GetChildInt
 * @param path   data node path,for example:config-child means child node of config
 * @param key
 * @return
 */
int ConfigFileUtil::GetChildInt(std::string &path, std::string &key)
{
    if (false == m_bLoaded)
    {
        return INVALID_VAL;
    }

    lua_getglobal(m_state, "GetChildInt");
    lua_pushstring(m_state, path.data());
    lua_pushstring(m_state, key.data());
    int ret = lua_pcall(m_state, 2, 1, 0);

    if (0 == ret)
    {
        //no error
        cout << "GetChildInt not error" << endl << flush;
        int val = static_cast<int>(lua_tonumber(m_state, -1));
        return val;
    }
    else
    {
        cout << "GetChildInt  error" << endl << flush;
        fatal_error_occur();
        return INVALID_VAL;
    }
}

double ConfigFileUtil::GetChildDouble(std::string &path, std::string &key)
{
    if (false == m_bLoaded)
    {
        return INVALID_VAL;
    }

    lua_getglobal(m_state, "GetChildDouble");
    lua_pushstring(m_state, path.data());
    lua_pushstring(m_state, key.data());
    int ret = lua_pcall(m_state, 2, 1, 0);

    if (0 == ret)
    {
        //no error
        cout << "GetChildDouble not error" << endl << flush;
        double val = lua_tonumber(m_state, -1);
        cout << val << endl << flush;
        return val;
    }
    else
    {
        cout << "GetChildDouble  error" << endl << flush;
        fatal_error_occur();
        return INVALID_VAL;
    }
}

std::string ConfigFileUtil::GetChildString(std::string &path, std::string &key)
{
    if (false == m_bLoaded)
    {
        return std::string("");
    }

    lua_getglobal(m_state, "GetChildString");
    lua_pushstring(m_state, path.data());
    lua_pushstring(m_state, key.data());
    int ret = lua_pcall(m_state, 2, 1, 0);

    if (0 == ret)
    {
        //no error
        cout << "GetChildString not error" << endl << flush;
        std::string val = std::string(lua_tostring(m_state, -1));
        return val;
    }
    else
    {
        cout << "GetChildString  error" << endl << flush;
        fatal_error_occur();
        return std::string("");
    }
}

int ConfigFileUtil::GetChildIntArray(std::vector<int> &buf, std::string &path, std::string &key)
{
    if (false == m_bLoaded)
    {
        return -1;
    }

    lua_getglobal(m_state, "GetChildIntArray");
    lua_pushstring(m_state, path.data());
    lua_pushstring(m_state, key.data());
    int ret = lua_pcall(m_state, 2, 0, 0);

    if (0 == ret)
    {
        //no error
        cout << "GetChildIntArray not error" << endl << flush;
        buf.clear();
        for (int i = 0; i < m_int_array.size(); ++i)
        {
            buf.push_back(m_int_array[i]);
        }
    }
    else
    {
        cout << "GetChildIntArray error" << endl << flush;
        fatal_error_occur();
        return -2;
    }
    return 0;


}

int ConfigFileUtil::GetChildDoubleArray(std::vector<double> &buf, std::string &path, std::string &key)
{
    if (false == m_bLoaded)
    {
        return -1;
    }

    lua_getglobal(m_state, "GetChildDoubleArray");
    lua_pushstring(m_state, path.data());
    lua_pushstring(m_state, key.data());
    int ret = lua_pcall(m_state, 2, 0, 0);

    if (0 == ret)
    {
        //no error
        cout << "GetChildDoubleArray not error" << endl << flush;
        buf.clear();
        for (int i = 0; i < m_double_array.size(); ++i)
        {
            buf.push_back(m_double_array[i]);
        }
    }
    else
    {
        cout << "GetChildDoubleArray error" << endl << flush;
        fatal_error_occur();
        return -2;
    }
    return 0;
}


int ConfigFileUtil::GetChildStringArray(std::vector<std::string> &buf, std::string &path, std::string &key)
{
    if (false == m_bLoaded)
    {
        return -1;
    }

    lua_getglobal(m_state, "GetChildStringArray");
    lua_pushstring(m_state, path.data());
    lua_pushstring(m_state, key.data());
    int ret = lua_pcall(m_state, 2, 0, 0);

    if (0 == ret)
    {
        //no error
        cout << "GetChildStringArray not error" << endl << flush;
        buf.clear();
        for (int i = 0; i < m_str_array.size(); ++i)
        {
            buf.push_back(m_str_array[i]);
        }
    }
    else
    {
        cout << "GetChildStringArray error" << endl << flush;
        fatal_error_occur();
        return -2;
    }
    return 0;

}

void ConfigFileUtil::load_lua_libs()
{
    if (NULL == m_state)
    {
        m_state = luaL_newstate();
        luaL_openlibs(m_state);
    }
}

void ConfigFileUtil::fatal_error_occur()
{
    m_desc = std::string(lua_tostring(m_state, -1));
    m_bLoaded = false;
}
void ConfigFileUtil::warning_error_occur()
{

}

lua的一个简单配置:

local Config = {};
Config={
 
    Kp={2.0,2.0},
    Kd={0.01,0.01},
    child1_node={
        child2_node={
            data={123,999.0,1444} --data is the what we want to read
        }
    }
};

return Config;

c++使用演示:

    ConfigFileUtil config;
    std::string config_file = "/home/test/config/LoadConfig.lua";
    config.Init(config_file);
    std::string path = std::string("Config-child1_node->child2_node");
    std::string key = std::string("data");
    std::vector<double> buf1;
    config.GetChildDoubleArray(buf1, path, key);

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值