惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

aimingoo的专栏
aimingoo的专栏
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Blog — PlanetScale
Blog — PlanetScale
博客园 - Franky
The GitHub Blog
The GitHub Blog
F
Fortinet All Blogs
Microsoft Azure Blog
Microsoft Azure Blog
I
InfoQ
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tailwind CSS Blog
博客园 - 三生石上(FineUI控件)
Apple Machine Learning Research
Apple Machine Learning Research
D
Docker
Google DeepMind News
Google DeepMind News
GbyAI
GbyAI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Proofpoint News Feed
N
Netflix TechBlog - Medium
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Engineering at Meta
Engineering at Meta
H
Help Net Security
B
Blog
宝玉的分享
宝玉的分享

博客园 - 海乐学习

VS2026创建.net8的控制台程序并能在银河麒麟V10的Liunx上运行 在麒麟系统中卸载RabbitMQ Java Maven 开发的常用命令 C语言开发的常用命令 三汇Linux配置Config说明 Java实现优雅的关闭程序并执行清理流程的写法 C语言开发中优雅的关闭程序并执行清理流程的写法 将C语言开发的程序做成 麒麟系统的服务(Systemd 标准服务,Linux 通用) 实现开机自启动 ZeroMQ的DEALER双帧结构(路由空帧 + 业务帧)(支持异步收发、主动推送事件)C写服务端 java写客户端 ZeroMQ中ZMQ_DEALER单帧数据(支持异步收发、主动推送事件)C写服务端 java写客户端 win10系统中 关闭专注助手 执行 xx.sh 脚本文件时出现: /bin/bash^M:解释器错误: 没有那个文件或目录 运行编译打包好的 xxx.jar 中没有主清单属性 出现这个错误 将Java编译的 .jar文件做成 麒麟系统的服务(Systemd 标准服务,Linux 通用) 实现开机自启动 将Java编译的 .jar文件做成windows服务 实现开机自启动 方法二 RabbitMQ在麒麟系统中离线安装说明 VMware启动虚似机后出现 无法获取快照信息: 锁定文件失败 模块“Snapshot”启动失败。未能启动虚拟机。 C语言在Linux中开发完整Demo包含读配置文件写日志和定时器Timer 麒麟V10 Server系统中搭建C语言开发环境 麒麟ServerV10 修改IP4地址 麒麟ServerV10 配置IP4 当系统中有两个版本的Maven时,用IDEA创建Maven有时会出错 麒麟ServerV10安装 espeak-ng 和 ffmpeg 方法 C语言在Linux中开发没有界面纯后台运行的Demo程序(含日志和Timer) C语言在Linux中开发使用定时器Timer在界面上显示时间 C语言在Linux中开发带界面的程序(含每小时日志) C语言在Linux中开发第一个项目Hello Word 在apache-maven项目中使用log4写日志 在apache-maven项目中解决中文乱码问题 在apache-maven项目中读取配置文件
C语言在Linux中开发读取配置文件app.conf
海乐学习 · 2026-05-04 · via 博客园 - 海乐学习

C语言在Linux中开发读取配置文件app.conf

在工程根目录下创建app.conf文件

注:app.conf 和 MyCServer.c 必须在同一目录下

image

 app.conf

# app.conf 全局配置文件
# 格式: Key=Value (支持首尾空格,注释用 # 或 ;)
TimerEnabled = 1
LogLevel    = 2
MaxConnections = 200
ServerIP    = 192.168.1.100
ServerPort  = 9000
LogDir      = /var/log/mycserver

MyCServer.h

//集中定义所有配置项(按需增删)
typedef struct {
    int     timer_enabled;       // 定时器开关:0/1
    int     log_level;          // 日志级别:0~3
    int     max_connections;    // 最大连接数
    char    server_ip[32];      // 监听IP
    int     server_port;        // 监听端口
    char    log_dir[128];       // 日志目录
    // ... 后续新增配置项直接在此添加 ...
} AppConfig;

/*========  函数声明 ========= */
int LoadAppConfig(const char* path, AppConfig* cfg);

MyCServer.c

定义全局配置实例

/*====================== 常量 ======================注:常量后面没有分号 */
#define CONFIG_FILE_PATH "app.conf" //配置文件路径(建议与可执行文件同目录)

// 全局配置实例(初始化为0,加载时会覆盖)
AppConfig g_cfg = {0};

主函数

int main(void){

    //加载app.conf配置文件并赋值到g_cfg
    LoadAppConfig(CONFIG_FILE_PATH, &g_cfg);
 
    printf("g_cfg.timer_enabled 开关:%d\n", g_cfg.timer_enabled);
 
    return 0;
}

读配置文件函数  注:app.conf 和 MyCServer.c 必须在同一目录下

/**
 * @brief 安全解析配置文件,填充 SysConfig 结构体
 * @param path 配置文件路径
 * @param cfg  输出参数:配置结构体指针
 * @return 0 成功,-1 文件缺失(使用默认值)
 */
int LoadAppConfig(const char* path, AppConfig* cfg)
{
    //1. 设置安全默认值(防止配置缺失导致未定义行为)
    cfg->timer_enabled    = 0;
    cfg->log_level        = 2;
    cfg->max_connections  = 100;
    snprintf(cfg->server_ip, sizeof(cfg->server_ip), "0.0.0.0");
    cfg->server_port      = 8080;
    snprintf(cfg->log_dir, sizeof(cfg->log_dir), "./logs");

    FILE* fp = fopen(path, "r");
    if (!fp) {
        Log_Write("[配置][警告] 未找到 %s,已启用全部默认值", path);
        return -1;
    }

    char line[512];
    while (fgets(line, sizeof(line), fp)) {
        // 跳过行首空白
        char* p = line;
        while (*p && isspace((unsigned char)*p)) p++;
        
        // 跳过注释(# / ;) 和空行
        if (*p == '\0' || *p == '#' || *p == ';') continue;

        // 查找等号分隔符
        char* eq = strchr(p, '=');
        if (!eq) continue;
        *eq = '\0';  // 截断,此时 p 指向 key,eq+1 指向 value

        char* key = p;
        char* val = eq + 1;

        // 清理 key 尾部空格
        char* k_end = key + strlen(key) - 1;
        while (k_end > key && isspace((unsigned char)*k_end)) *k_end-- = '\0';
        // 清理 val 首尾空格
        while (*val && isspace((unsigned char)*val)) val++;
        char* v_end = val + strlen(val) - 1;
        while (v_end >= val && isspace((unsigned char)*v_end)) *v_end-- = '\0';

        //核心匹配区(按需扩展 if-else 链)
        if (strcmp(key, "TimerEnabled") == 0) {
            //C语言的布尔归一化逻辑 只要 atoi(val) 不是 0,就强制赋值为 1。
            //cfg->timer_enabled = (atoi(val) != 0) ? 1 : 0;
            cfg->timer_enabled = atoi(val);
        }
        else if (strcmp(key, "LogLevel") == 0) {
            int lvl = atoi(val);
            cfg->log_level = (lvl >= 0 && lvl <= 3) ? lvl : 2;
        }
        else if (strcmp(key, "MaxConnections") == 0) {
            cfg->max_connections = atoi(val);
            if (cfg->max_connections <= 0) cfg->max_connections = 100;
        }
        else if (strcmp(key, "ServerIP") == 0) {
            strncpy(cfg->server_ip, val, sizeof(cfg->server_ip) - 1);
            cfg->server_ip[sizeof(cfg->server_ip) - 1] = '\0';
        }
        else if (strcmp(key, "ServerPort") == 0) {
            int port = atoi(val);
            cfg->server_port = (port > 0 && port < 65536) ? port : 8080;
        }
        else if (strcmp(key, "LogDir") == 0) {
            strncpy(cfg->log_dir, val, sizeof(cfg->log_dir) - 1);
            cfg->log_dir[sizeof(cfg->log_dir) - 1] = '\0';
        }
        else {
            Log_Write("[配置][警告] 忽略未知配置项: %s", key);
        }
    }
    fclose(fp);

    //打印加载摘要
    Log_Write("[配置] 加载完成 -> TimerEnabled=%d, LogLevel=%d, IP=%s:%d, MaxConn=%d",
              cfg->timer_enabled, cfg->log_level, cfg->server_ip, cfg->server_port, cfg->max_connections);
    return 0;
}