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