侧边栏壁纸
博主头像
银河驿站 博主等级

行动起来,活在当下

  • 累计撰写 96 篇文章
  • 累计创建 17 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

跨平台环境变量读写

Administrator
2026-07-31 / 0 评论 / 0 点赞 / 1 阅读 / 0 字

env_var — 跨平台环境变量读写(C 语言)

一套跨平台(Linux/macOS/Windows)的 C 语言环境变量工具函数,涵盖读取、设置、删除,以及把数字字符串安全解析为 int/long

接口一览

函数 作用 返回码
env_get(name, out, size) 读环境变量到缓冲区 0 成功 / -1 参数无效 / -2 未设置 / -3 缓冲不足
env_set(name, value, overwrite) 设置环境变量(overwrite≠0 覆盖) 0 成功 / -1 失败
env_unset(name) 删除环境变量 0 成功 / -1 失败
env_get_long(name, *out) 数字字符串 → long 0 成功 / -2 未设置 / -3 非法 / -4 溢出
env_get_int(name, *out) 数字字符串 → int(含范围检查) 同上
env_get_long_def(name, def) 带默认值的 long 读取 成功返回解析值,否则返回 def
env_get_int_def(name, def) 带默认值的 int 读取 同上

env_var.h

#ifndef ENV_VAR_H
#define ENV_VAR_H

#include <stddef.h>

/*
 * 返回值约定:
 *   0   成功
 *  -1   参数无效(NULL 指针 / size 为 0)
 *  -2   环境变量不存在
 *  -3   缓冲区不足 / 字符串不是合法整数
 *  -4   数值溢出(超过 long / int 范围)
 */

int env_get(const char *name, char *out, size_t size);
int env_set(const char *name, const char *value, int overwrite);
int env_unset(const char *name);

int env_get_long(const char *name, long *out);
int env_get_int(const char *name, int *out);
long env_get_long_def(const char *name, long def);
int  env_get_int_def(const char *name, int def);

#endif /* ENV_VAR_H */

env_var.c

#include "env_var.h"

#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>

#if defined(_WIN32)
#  include <windows.h>
#endif

int env_get(const char *name, char *out, size_t size)
{
    if (name == NULL || out == NULL || size == 0)
        return -1;

#if defined(_WIN32)
    DWORD need = GetEnvironmentVariableA(name, out, (DWORD)size);
    if (need == 0) {
        if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
            return -2;
        return -1;
    }
    if (need > (DWORD)size)
        return -3;
    return 0;
#else
    const char *v = getenv(name);
    if (v == NULL)
        return -2;
    if (strlen(v) >= size)
        return -3;
    strcpy(out, v);
    return 0;
#endif
}

int env_set(const char *name, const char *value, int overwrite)
{
    if (name == NULL || value == NULL)
        return -1;

#if defined(_WIN32)
    if (!SetEnvironmentVariableA(name, value))
        return -1;
    return 0;
#else
    if (setenv(name, value, overwrite ? 1 : 0) != 0)
        return -1;
    return 0;
#endif
}

int env_unset(const char *name)
{
    if (name == NULL)
        return -1;

#if defined(_WIN32)
    if (!SetEnvironmentVariableA(name, NULL))
        return -1;
    return 0;
#else
    if (unsetenv(name) != 0)
        return -1;
    return 0;
#endif
}

int env_get_long(const char *name, long *out)
{
    if (name == NULL || out == NULL)
        return -1;

    char buf[64];
    int rc = env_get(name, buf, sizeof buf);
    if (rc != 0)
        return rc;

    if (buf[0] == '\0')
        return -3;

    errno = 0;
    char *end = NULL;
    long val = strtol(buf, &end, 10);

    if (errno == ERANGE)
        return -4;
    if (end == buf)
        return -3;
    while (*end == ' ' || *end == '\t')
        end++;
    if (*end != '\0')
        return -3;

    *out = val;
    return 0;
}

int env_get_int(const char *name, int *out)
{
    long v;
    int rc = env_get_long(name, &v);
    if (rc != 0)
        return rc;
    if (v < INT_MIN || v > INT_MAX)
        return -4;
    *out = (int)v;
    return 0;
}

long env_get_long_def(const char *name, long def)
{
    long v;
    return (env_get_long(name, &v) == 0) ? v : def;
}

int env_get_int_def(const char *name, int def)
{
    int v;
    return (env_get_int(name, &v) == 0) ? v : def;
}

用法示例

#include "env_var.h"
#include <stdio.h>

int main(void) {
    int port;
    switch (env_get_int("HTTP_PORT", &port)) {
        case 0:  printf("port=%d\n", port); break;
        case -2: printf("HTTP_PORT 未设置\n"); break;
        case -3: printf("HTTP_PORT 不是合法整数\n"); break;
        case -4: printf("HTTP_PORT 超出 int 范围\n"); break;
    }
    int timeout = env_get_int_def("HTTP_TIMEOUT", 30);  // 缺失/非法走默认
    printf("timeout=%d\n", timeout);
    return 0;
}
gcc main.c env_var.c -o demo
export HTTP_PORT=8080
./demo

关键说明

  1. 整数解析用 strtol 而非 atoiatoi 失败静默返回 0、溢出未定义行为,无法区分“未设置”与“值为 0”。本实现校验了空串、ERANGE 溢出、尾随非法字符、long→int 截断。
  2. 跨平台差异:Windows 用 GetEnvironmentVariableA/SetEnvironmentVariableA(大小写不敏感);POSIX 用 getenv/setenv/unsetenv(大小写敏感)。两者都只改当前进程环境。
  3. 性能getenv 每次线性扫描 environ、不缓存,极热路径建议启动时缓存一次。
  4. 线程安全:POSIX getenv 在环境被并发修改时非线程安全,必要时缓存或加锁。
0

评论区