使用 C 语言的 setenv 函数访问环境变量

Jinku Hu 2023年1月30日 2021年2月28日
  1. 在 C 语言中使用 setenv 函数导出环境变量
  2. 使用 envp 变量在 C 语言中遍历定义的环境变量
  3. 使用 environ 变量在 C 语言中遍历定义的环境变量
使用 C 语言的 setenv 函数访问环境变量

本文将介绍在 C 语言中使用 setenv 函数导出环境变量的几种方法。

在 C 语言中使用 setenv 函数导出环境变量

在 Unix-base 系统上运行的每个程序都有一个环境,它收集了主要由 shell 和其他用户空间程序使用的变量值对。程序可以用 getenv 函数检索单个环境变量及其值。但如果要定义一个新的变量或改变现有的变量,则应调用 setenv 函数。它需要三个参数,第一个和第二个参数是 char 指针,分别指向变量名和它的值。第三个参数的类型是 int,它指定如果环境中已经存在给定变量的值是否应该被覆盖。这个参数的非零值表示覆盖行为,零值表示相反。

但请注意,遍历所有定义的环境变量,需要访问名为-environ 的特殊全局变量,它是一个以 NULL 结尾的字符串数组。另外,也可以声明 main 函数,第三个参数 envp 来访问变量。在下面的例子中,我们在调用 setenv 函数之前和之后同时打印 enironenvp 指针。请注意,调用后,envp 指针的值是一样的,而 environ 的值已经改变了。

#include <stdio.h>
#include <stdlib.h>

extern char **environ;

int main(int argc, const char *argv[], const char *envp[]) {

    printf("environ:  %p\n", environ);
    printf("envp:     %p\n", envp);

    setenv("NEW_VAR", "new_value", 1);

    puts("----Added NEW_VAR----");
    printf("environ:  %p\n", environ);
    printf("envp:     %p\n", envp);

    exit(EXIT_SUCCESS);
}

输出:

environ:  0x7fffa05a7fe8
envp:     0x7fffa05a7fe8
----Added NEW_VAR----
environ:  0x5646431276b0
envp:     0x7fffa05a7fe8

使用 envp 变量在 C 语言中遍历定义的环境变量

前面的代码例子说明了为什么应该避免在调用 setenv 函数后使用 main 函数参数 envp 检索环境变量。当调用 setenv 函数时,环境被重新定位,但 envp 仍然指向旧环境。下面的示例代码通过用 setenv 调用定义一个新的变量,然后遍历 envp 指针数组来演示错误的行为。请注意,如果找到名为 NEW_VAR 的变量,我们还利用 goto 语句跳转到循环的末端。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, const char *argv[], const char *envp[]) {

    if (setenv("NEW_VAR", "new_value", 1) != 0) {
        perror("setenv");
        exit(EXIT_FAILURE);
    }

    if (envp != NULL) {
        for (size_t i = 0; envp[i] != NULL; ++i) {
            if (strcmp(envp[i], "NEW_VAR=new_value") == 0) {
                puts(envp[i]);
                goto END;
            }
        }
        printf("No such variable found!\n");
    } END:

    exit(EXIT_SUCCESS);
}

输出:

No such variable found!

使用 environ 变量在 C 语言中遍历定义的环境变量

由于前面的解决方案找不到新定义的变量,我们应该使用外部声明的 environ 变量。在这种情况下,我们包含了多个预处理器条件语句,以使代码在不同的系统中可移植,但在大多数基于 UNIX 的系统中只需要 extern char **environ。一旦声明,我们就可以使用我们在上一个例子中实现的相同的循环来遍历变量列表。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if defined (_POSIX_) || defined (__USE_POSIX)
extern char **environ;
#elif defined(_WIN32)
_CRTIMP extern char **_environ;
#endif

int main(void) {

    if (setenv("NEW_VAR", "new_value", 1) != 0) {
        perror("setenv");
        exit(EXIT_FAILURE);
    }

    if (environ != NULL) {
        for (size_t i = 0; environ[i] != NULL; ++i) {
            if (strcmp(environ[i], "NEW_VAR=new_value") == 0) {
                puts(environ[i]);
                goto END;
            }
        }
        printf("No such variable found!\n");
    } END:

    exit(EXIT_SUCCESS);
}

输出:

NEW_VAR=new_value
Author: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn