14.3.2 环境访问
程序运行时会与宿主环境交换信息,例如命令行参数、环境表项和外部命令执行能力。标准库在 <stdlib.h> 中提供了最小且可移植的访问接口。
1. 环境表项读取:getenv
getenv 通过键名读取环境表中的字符串值。返回指针可能为 NULL,也可能指向由实现管理的存储,因此调用方不应修改其内容。
c
#include <stdlib.h>
#include <stdio.h>
int main(void) {
const char *home = getenv("HOME");
if (home != NULL) {
printf("HOME=%s\n", home);
}
return 0;
}1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
例如环境中存在 HOME=/home/alice 时,输出为:
bash
HOME=/home/alice
如果环境中没有名为 HOME 的表项,程序不会输出任何内容。
2. 命令行参数
宿主实现中,main 常见原型为 int main(int argc, char *argv[])。argc 表示参数个数,argv 保存参数字符串数组,argv[0] 通常是程序名。读取参数时应先检查下标边界,再做解析。
c
#include <stdio.h>
int main(int argc, char *argv[]) {
for (int i = 0; i < argc; ++i) {
printf("argv[%d] = %s\n", i, argv[i]);
}
return 0;
}1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
例如以 ./args alpha beta 启动程序,且实现把调用时的程序名保存到 argv[0],输出示例为:
bash
argv[0] = ./args argv[1] = alpha argv[2] = beta
3. 外部命令执行:system
system 会把命令字符串交给宿主命令处理器执行。它适合教学示例和简单脚本桥接,但在安全敏感场景应谨慎使用,尤其是命令字符串来自不可信输入时。
c
#include <stdlib.h>
int main(void) {
return system("echo hello");
}1
2
3
4
5
2
3
4
5
4. getenv 返回值生存期
getenv 返回的指针指向由实现管理的存储,不应由调用方释放,也不应原地修改。若后续流程需要长期保存该字符串,建议复制到自有对象中再使用。
5. 写环境表的可移植性
ISO C 只标准化了读取接口 getenv,环境表写入接口通常属于平台扩展。若代码依赖修改环境表,应在文档中明确平台前提,并提供不可用时的替代路径。
6. 参数解析应集中在入口层
命令行参数最好在程序入口统一解析为内部配置对象,再把该配置传给后续模块。这样做可以把“文本到类型”的转换与校验集中管理,避免多个模块重复解析同一参数导致语义分叉。
c
#include <errno.h>
#include <stdlib.h>
int parse_port(const char *s, int *out) {
char *end = NULL;
errno = 0;
long v = strtol(s, &end, 10);
if (errno != 0 || end == s || *end != '\0' || v < 1 || v > 65535) {
return -1;
}
*out = (int)v;
return 0;
}1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13