包装c++的variant给c用
variant_wrapper.cpp
#include <variant>
#include <unordered_map>
#include <cstring>
#include <cstdio>
#include <new>
#include <memory>
#include <functional>
#include <cstdlib>
enum TypeId {
TYPE_INVALID = -1,
TYPE_INT = 0,
TYPE_FLOAT = 1,
TYPE_DOUBLE = 2,
TYPE_STR = 3,
TYPE_CUSTOM_BASE = 100
};
struct CustomTypeOps {
size_t size;
void (*copy)(const void* src, void* dest);
void (*destroy)(void* data);
};
static std::unordered_map<TypeId, CustomTypeOps> g_type_registry;
static int g_next_custom_type = TYPE_CUSTOM_BASE;
extern "C" TypeId cvariant_register_custom_type(size_t size,
void (*copy)(const void*, void*),
void (*destroy)(void*)) {
TypeId id = static_cast<TypeId>(g_next_custom_type++);
g_type_registry[id] = {size, copy, destroy};
return id;
}
using VariantData = std::variant<
int,
float,
double,
char*,
std::unique_ptr<void, std::function<void(void*)>>
>;
typedef struct CVariant {
VariantData data;
TypeId type_id;
} CVariant;
static const CustomTypeOps* get_custom_ops(TypeId id) {
auto it = g_type_registry.find(id);
return (it != g_type_registry.end()) ? &it->second : nullptr;
}
extern "C" {
CVariant* cvariant_create() {
try {
return new CVariant{{}, TYPE_INVALID};
} catch (const std::bad_alloc&) {
return nullptr;
}
}
void cvariant_destroy(CVariant* var) {
if (!var) return;
if (var->type_id == TYPE_STR) {
if (std::holds_alternative<char*>(var->data)) {
char* str = std::get<char*>(var->data);
free(str);
}
}
delete var;
}
void cvariant_set_int(CVariant* var, int value) {
if (var) {
if (var->type_id == TYPE_STR && std::holds_alternative<char*>(var->data)) {
free(std::get<char*>(var->data));
}
var->data = value;
var->type_id = TYPE_INT;
}
}
void cvariant_set_float(CVariant* var, float value) {
if (var) {
if (var->type_id == TYPE_STR && std::holds_alternative<char*>(var->data)) {
free(std::get<char*>(var->data));
}
var->data = value;
var->type_id = TYPE_FLOAT;
}
}
void cvariant_set_double(CVariant* var, double value) {
if (var) {
if (var->type_id == TYPE_STR && std::holds_alternative<char*>(var->data)) {
free(std::get<char*>(var->data));
}
var->data = value;
var->type_id = TYPE_DOUBLE;
}
}
void cvariant_set_str(CVariant* var, const char* value) {
if (var) {
if (var->type_id == TYPE_STR && std::holds_alternative<char*>(var->data)) {
free(std::get<char*>(var->data));
}
if (value) {
char* str = (char*)malloc(strlen(value) + 1);
if (str) {
strcpy(str, value);
var->data = str;
var->type_id = TYPE_STR;
return;
}
}
var->data = (char*)nullptr;
var->type_id = TYPE_STR;
}
}
int cvariant_set_custom(CVariant* var, TypeId type_id, const void* data) {
if (!var || !data || type_id < TYPE_CUSTOM_BASE) return -1;
if (var->type_id == TYPE_STR && std::holds_alternative<char*>(var->data)) {
free(std::get<char*>(var->data));
}
const auto* ops = get_custom_ops(type_id);
if (!ops) return -1;
void* storage = malloc(ops->size);
if (!storage) return -1;
ops->copy(data, storage);
var->data = std::unique_ptr<void, std::function<void(void*)>>(
storage,
[type_id](void* ptr) {
const auto* ops = get_custom_ops(type_id);
if (ops) ops->destroy(ptr);
free(ptr);
}
);
var->type_id = type_id;
return 0;
}
TypeId cvariant_get_type(const CVariant* var) {
return var ? var->type_id : TYPE_INVALID;
}
int cvariant_get_int(const CVariant* var) {
if (var && var->type_id == TYPE_INT && std::holds_alternative<int>(var->data)) {
return std::get<int>(var->data);
}
fprintf(stderr, "cvariant: 类型错误(预期int)\n");
return 0;
}
float cvariant_get_float(const CVariant* var) {
if (var && var->type_id == TYPE_FLOAT && std::holds_alternative<float>(var->data)) {
return std::get<float>(var->data);
}
fprintf(stderr, "cvariant: 类型错误(预期float)\n");
return 0.0f;
}
double cvariant_get_double(const CVariant* var) {
if (var && var->type_id == TYPE_DOUBLE && std::holds_alternative<double>(var->data)) {
return std::get<double>(var->data);
}
fprintf(stderr, "cvariant: 类型错误(预期double)\n");
return 0.0;
}
const char* cvariant_get_str(const CVariant* var) {
if (var && var->type_id == TYPE_STR && std::holds_alternative<char*>(var->data)) {
return std::get<char*>(var->data);
}
fprintf(stderr, "cvariant: 类型错误(预期字符串)\n");
return nullptr;
}
int cvariant_get_custom(const CVariant* var, void* dest) {
if (!var || !dest || var->type_id < TYPE_CUSTOM_BASE) return -1;
const auto* ops = get_custom_ops(var->type_id);
if (!ops) return -1;
if (std::holds_alternative<std::unique_ptr<void, std::function<void(void*)>>>(var->data)) {
const void* src = std::get<std::unique_ptr<void, std::function<void(void*)>>>(var->data).get();
ops->copy(src, dest);
return 0;
}
return -1;
}
}
cvariant.h
#ifndef CVARIANT_H
#define CVARIANT_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
TYPE_INVALID = -1,
TYPE_INT = 0,
TYPE_FLOAT = 1,
TYPE_DOUBLE = 2,
TYPE_STR = 3,
TYPE_CUSTOM_BASE = 100
} TypeId;
typedef struct CVariant CVariant;
struct CVariant* cvariant_create();
void cvariant_destroy(struct CVariant* var);
TypeId cvariant_register_custom_type(size_t size,
void (*copy)(const void* src, void* dest),
void (*destroy)(void* data));
void cvariant_set_int(struct CVariant* var, int value);
void cvariant_set_float(struct CVariant* var, float value);
void cvariant_set_double(struct CVariant* var, double value);
void cvariant_set_str(struct CVariant* var, const char* value);
int cvariant_set_custom(struct CVariant* var, TypeId type_id, const void* data);
TypeId cvariant_get_type(const struct CVariant* var);
int cvariant_get_int(const struct CVariant* var);
float cvariant_get_float(const struct CVariant* var);
double cvariant_get_double(const struct CVariant* var);
const char* cvariant_get_str(const struct CVariant* var);
int cvariant_get_custom(const struct CVariant* var, void* dest);
#ifdef __cplusplus
}
#endif
#endif
build shared lib
g++ -shared -fPIC variant_wrapper.cpp -o cvariant.dll -Wl,--out-implib=libcvariant.a
conffget.c
#include "cvariant.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
static char* strndup(const char* s, size_t n) {
if (s == NULL) return NULL;
size_t len = strlen(s);
if (n < len) len = n;
char* result = (char*)malloc(len + 1);
if (result == NULL) return NULL;
memcpy(result, s, len);
result[len] = '\0';
return result;
}
typedef struct ConfigNode {
char* section;
char* key;
CVariant* value;
struct ConfigNode* next;
} ConfigNode;
typedef struct {
ConfigNode* head;
char* current_section;
} ConfigParser;
static ConfigParser* parser_init() {
ConfigParser* parser = (ConfigParser*)malloc(sizeof(ConfigParser));
parser->head = NULL;
parser->current_section = NULL;
return parser;
}
static void parser_free(ConfigParser* parser) {
ConfigNode* node = parser->head;
while (node) {
ConfigNode* next = node->next;
free(node->section);
free(node->key);
cvariant_destroy(node->value);
free(node);
node = next;
}
free(parser->current_section);
free(parser);
}
static char* trim(char* str) {
if (!str) return NULL;
while (isspace((unsigned char)*str)) str++;
if (*str) {
char* end = str + strlen(str) - 1;
while (end > str && isspace((unsigned char)*end)) end--;
*(end + 1) = '\0';
}
return str;
}
static void set_value_by_type(CVariant* var, const char* value_str) {
char* endptr;
if (strcmp(value_str, "true") == 0 || strcmp(value_str, "yes") == 0) {
cvariant_set_int(var, 1);
return;
}
if (strcmp(value_str, "false") == 0 || strcmp(value_str, "no") == 0) {
cvariant_set_int(var, 0);
return;
}
long int_val = strtol(value_str, &endptr, 10);
if (*endptr == '\0') {
cvariant_set_int(var, (int)int_val);
return;
}
double float_val = strtod(value_str, &endptr);
if (*endptr == '\0') {
cvariant_set_double(var, float_val);
return;
}
if (value_str[0] == '"' && value_str[strlen(value_str)-1] == '"') {
char* str_val = strndup(value_str + 1, strlen(value_str) - 2);
cvariant_set_str(var, str_val);
free(str_val);
return;
}
cvariant_set_str(var, value_str);
}
static void add_config_node(ConfigParser* parser, const char* key, const char* value) {
if (!parser->current_section || !key || !value) return;
ConfigNode* node = (ConfigNode*)malloc(sizeof(ConfigNode));
node->section = strdup(parser->current_section);
node->key = strdup(key);
node->value = cvariant_create();
set_value_by_type(node->value, value);
node->next = parser->head;
parser->head = node;
}
static int parse_ini_file(ConfigParser* parser, const char* filename) {
FILE* f = fopen(filename, "r");
if (!f) {
fprintf(stderr, "无法打开文件: %s\n", filename);
return -1;
}
char line[1024];
int line_num = 0;
while (fgets(line, sizeof(line), f)) {
line_num++;
char* content = trim(line);
if (*content == '\0' || *content == ';' || *content == '#') continue;
if (*content == '[' && content[strlen(content)-1] == ']') {
free(parser->current_section);
parser->current_section = strndup(content + 1, strlen(content) - 2);
continue;
}
char* eq_pos = strchr(content, '=');
if (eq_pos) {
*eq_pos = '\0';
char* key = trim(content);
char* value = trim(eq_pos + 1);
add_config_node(parser, key, value);
} else {
fprintf(stderr, "警告: 无效行 %d: %s\n", line_num, content);
}
}
fclose(f);
return 0;
}
static int query_config(ConfigParser* parser, const char* query) {
char* dot_pos = strchr(query, '.');
if (!dot_pos) {
fprintf(stderr, "查询格式错误,应为: 节名.键名\n");
return -1;
}
char* section = strndup(query, dot_pos - query);
char* key = strdup(dot_pos + 1);
ConfigNode* node = parser->head;
while (node) {
if (strcmp(node->section, section) == 0 && strcmp(node->key, key) == 0) {
switch (cvariant_get_type(node->value)) {
case TYPE_INT:
if (strcmp(key, "enable") == 0 || strcmp(key, "active") == 0) {
printf("%s\n", cvariant_get_int(node->value) ? "true" : "false");
} else {
printf("%d\n", cvariant_get_int(node->value));
}
break;
case TYPE_DOUBLE:
printf("%g\n", cvariant_get_double(node->value));
break;
case TYPE_STR:
printf("%s\n", cvariant_get_str(node->value));
break;
default:
printf("未知类型\n");
}
free(section);
free(key);
return 0;
}
node = node->next;
}
fprintf(stderr, "未找到配置项: %s\n", query);
free(section);
free(key);
return -1;
}
static void list_all_configs(ConfigParser* parser) {
ConfigNode* node = parser->head;
while (node) {
printf("[%s] %s = ", node->section, node->key);
switch (cvariant_get_type(node->value)) {
case TYPE_INT:
printf("%d (int)\n", cvariant_get_int(node->value));
break;
case TYPE_DOUBLE:
printf("%g (float)\n", cvariant_get_double(node->value));
break;
case TYPE_STR:
printf("%s (string)\n", cvariant_get_str(node->value));
break;
}
node = node->next;
}
}
static void print_help(const char* progname) {
printf("用法: %s [选项] <INI文件> [查询]\n", progname);
printf("解析INI配置文件并查询值(兼容Linux风格)\n");
printf("选项:\n");
printf(" -l 列出文件中所有配置项及类型\n");
printf(" -h 显示帮助信息\n");
printf("查询格式: 节名.键名(如 'server.port')\n");
printf("示例:\n");
printf(" %s config.ini server.port # 查询[server]节的port值\n", progname);
printf(" %s -l app.ini # 列出app.ini所有配置项\n", progname);
printf(" %s settings.ini log.enable # 查询[log]节的enable值(布尔型)\n", progname);
}
int main(int argc, char* argv[]) {
if (argc < 2) {
print_help(argv[0]);
return 1;
}
int list_mode = 0;
const char* filename = NULL;
const char* query = NULL;
if (strcmp(argv[1], "-h") == 0) {
print_help(argv[0]);
return 0;
} else if (strcmp(argv[1], "-l") == 0) {
if (argc < 3) {
print_help(argv[0]);
return 1;
}
list_mode = 1;
filename = argv[2];
} else {
filename = argv[1];
query = (argc >= 3) ? argv[2] : NULL;
if (!query) {
print_help(argv[0]);
return 1;
}
}
ConfigParser* parser = parser_init();
if (parse_ini_file(parser, filename) != 0) {
parser_free(parser);
return 1;
}
if (list_mode) {
list_all_configs(parser);
} else {
query_config(parser, query);
}
parser_free(parser);
return 0;
}
build confget.c
gcc -o confget.exe confget.c -L . -lcvariant
config.ini
; 示例配置文件
[server]
port = 8080
host = "localhost"
timeout = 30.5
enable = true
[log]
path = "C:\logs"
level = info
max_size = 1024
sample output
confget.exe config.ini server.port
confget.exe config.ini server.timeout
confget.exe config.ini server.enable
confget.exe config.ini log.path
confget.exe -l config.ini
probe1.c
#include "cvariant.h"
#include <stdio.h>
#include <string.h>
typedef struct { int x; int y; char name[32]; } Point;
static void point_copy(const void* src, void* dest);
static void point_destroy(void* data);
int main() {
TypeId point_type = cvariant_register_custom_type(
sizeof(Point),
point_copy,
point_destroy
);
printf("注册自定义类型 Point,ID: %d\n", point_type);
struct CVariant* var = cvariant_create();
if (!var) {
printf("创建变体失败\n");
return 1;
}
cvariant_set_int(var, 123);
printf("类型: %d (预期0), 值: %d\n", cvariant_get_type(var), cvariant_get_int(var));
cvariant_set_double(var, 3.1415926535);
printf("类型: %d (预期2), 值: %lf\n", cvariant_get_type(var), cvariant_get_double(var));
cvariant_set_str(var, "测试字符串");
printf("类型: %d (预期3), 值: %s\n", cvariant_get_type(var), cvariant_get_str(var));
Point p = {10, 20, "原点"};
cvariant_set_custom(var, point_type, &p);
if (cvariant_get_type(var) == point_type) {
Point p_out;
cvariant_get_custom(var, &p_out);
printf("类型: %d (预期自定义ID), 值: (%d, %d, %s)\n",
cvariant_get_type(var), p_out.x, p_out.y, p_out.name);
}
cvariant_destroy(var);
return 0;
}
static void point_copy(const void* src, void* dest) {
const Point* s = (const Point*)src;
Point* d = (Point*)dest;
d->x = s->x;
d->y = s->y;
strncpy(d->name, s->name, sizeof(d->name)-1);
}
static void point_destroy(void* data) {
}
probe2.c
#include "cvariant.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef enum {
RED,
GREEN,
BLUE,
BLACK,
WHITE
} Color;
typedef union {
int i;
float f;
double d;
} Number;
typedef struct {
Color color;
Number value;
char name[64];
} ComplexData;
static void color_copy(const void* src, void* dest) {
*(Color*)dest = *(const Color*)src;
}
static void color_destroy(void* data) {
}
static void number_copy(const void* src, void* dest) {
memcpy(dest, src, sizeof(Number));
}
static void number_destroy(void* data) {
}
static void complexdata_copy(const void* src, void* dest) {
const ComplexData* s = (const ComplexData*)src;
ComplexData* d = (ComplexData*)dest;
d->color = s->color;
d->value = s->value;
strncpy(d->name, s->name, sizeof(d->name)-1);
}
static void complexdata_destroy(void* data) {
}
int main() {
TypeId color_type = cvariant_register_custom_type(
sizeof(Color), color_copy, color_destroy
);
TypeId number_type = cvariant_register_custom_type(
sizeof(Number), number_copy, number_destroy
);
TypeId complex_type = cvariant_register_custom_type(
sizeof(ComplexData), complexdata_copy, complexdata_destroy
);
printf("注册类型ID:\n");
printf(" Color: %d\n", color_type);
printf(" Number: %d\n", number_type);
printf(" ComplexData: %d\n\n", complex_type);
struct CVariant* var = cvariant_create();
if (!var) {
fprintf(stderr, "创建变体失败\n");
return 1;
}
Color my_color = BLUE;
cvariant_set_custom(var, color_type, &my_color);
if (cvariant_get_type(var) == color_type) {
Color get_color;
cvariant_get_custom(var, &get_color);
printf("枚举类型测试:\n");
printf(" 存储的颜色: %d (BLUE对应值为2)\n", get_color);
}
Number my_num;
my_num.f = 3.14159f;
cvariant_set_custom(var, number_type, &my_num);
if (cvariant_get_type(var) == number_type) {
Number get_num;
cvariant_get_custom(var, &get_num);
printf("\n联合体类型测试:\n");
printf(" 存储的float值: %f\n", get_num.f);
}
ComplexData my_complex = {
.color = GREEN,
.value = {.d = 99.99},
.name = "示例数据"
};
cvariant_set_custom(var, complex_type, &my_complex);
if (cvariant_get_type(var) == complex_type) {
ComplexData get_complex;
cvariant_get_custom(var, &get_complex);
printf("\n复杂结构体测试:\n");
printf(" 颜色枚举值: %d (GREEN对应值为1)\n", get_complex.color);
printf(" 联合体double值: %lf\n", get_complex.value.d);
printf(" 名称: %s\n", get_complex.name);
}
cvariant_destroy(var);
return 0;
}
probe3.c
#include "cvariant.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
int id;
char* name;
float score;
} DynamicData;
static void dynamicdata_copy(const void* src, void* dest) {
const DynamicData* s = (const DynamicData*)src;
DynamicData* d = (DynamicData*)dest;
d->id = s->id;
d->score = s->score;
if (s->name) {
d->name = (char*)malloc(strlen(s->name) + 1);
strcpy(d->name, s->name);
} else {
d->name = NULL;
}
}
static void dynamicdata_destroy(void* data) {
DynamicData* d = (DynamicData*)data;
if (d->name) {
free(d->name);
d->name = NULL;
}
}
int main() {
TypeId dynamic_type = cvariant_register_custom_type(
sizeof(DynamicData),
dynamicdata_copy,
dynamicdata_destroy
);
printf("注册动态类型 ID: %d\n", dynamic_type);
DynamicData original;
original.id = 1001;
original.name = (char*)malloc(strlen("Alice") + 1);
strcpy(original.name, "Alice");
original.score = 95.5f;
printf("原始数据: id=%d, name=%s, score=%.1f\n",
original.id, original.name, original.score);
struct CVariant* var = cvariant_create();
cvariant_set_custom(var, dynamic_type, &original);
if (cvariant_get_type(var) == dynamic_type) {
DynamicData copy;
cvariant_get_custom(var, ©);
printf("从变体读取: id=%d, name=%s, score=%.1f\n",
copy.id, copy.name, copy.score);
}
free(original.name);
cvariant_destroy(var);
return 0;
}