60

How do I set an environment variable in C++?

  • They do not need to persist past program execution
  • They only need to be visible in the current process
  • Preference for platform independent but for my problem only needs to work on Win32/64

Thanks

alamar
  • 18,729
  • 4
  • 64
  • 97
Jesse Vogt
  • 16,229
  • 16
  • 59
  • 72

4 Answers4

65
NAME

       putenv - change or add an environment variable

SYNOPSIS

       #include &ltstdlib.h>

       int putenv(char *string);

DESCRIPTION
       The  putenv()  function adds or changes the value of environment
       variables.  The argument string is of the form name=value.  If name does
       not already exist in the environment, then string is added  to  the
       environment.   If name does exist, then the value of name in the
       environment is changed to value.  The string pointed to by string becomes
       part of the environment, so altering the string changes the environment.

On Win32 it's called _putenv I believe.

See SetEnvironmentVariable also if you're a fan of long and ugly function names.

ulidtko
  • 14,740
  • 10
  • 56
  • 88
alamar
  • 18,729
  • 4
  • 64
  • 97
  • 4
    Note to questioner - putenv is also supported in Win32. –  May 22 '09 at 19:16
  • 38
    Can we please use proper C++ header names? is appropriate (yeah, I know...it's a hangup of mine). – Harper Shelby May 22 '09 at 19:18
  • 5
    It is C as a Lord God intended. – alamar May 22 '09 at 19:19
  • 7
    stlib.h is a proper C header file - the question is tagged as C –  May 22 '09 at 19:20
  • Are you sure that the change isn't global on Windows ? – Bastien Léonard May 22 '09 at 19:56
  • 1
    "Sets the contents of the specified environment variable for the current process." – alamar May 22 '09 at 20:21
  • 2
    MSDN is explicit that _putenv() only applies to the current process. Apparently, it also only applies to the environment as made visible to the C runtime library, but the CRT functions that create new processes all supply the CRT's environment to the new process so you usually wouldn't notice. SetEnvironmentVariable() manipulates the actual process environment table. I don't know if that distinction matters in practice. To make global environment changes, you have to touch the Registry, so that is much harder to do by accident. – RBerteig May 22 '09 at 20:21
  • By the way, putenv() is not in the standard C library. It's defined by POSIX. That's why the Microsoft version starts with an underscore (unless you use the #define that enables POSIX functions, in which case oldnames.lib redirects putenv() -> _putenv() for you). – bk1e May 25 '09 at 18:54
  • 9
    SetEnvironmentVariable is certainly not an ugly function name; it's much more descriptive than putenv. – Valentein Nov 16 '11 at 18:52
  • 1
    Note: setenv differs from putenv in that it makes a copy of the string instead of forcing the user to ensure it's kept alive as long as needed. – Mr Fooz Feb 25 '13 at 18:21
  • @RBerteig, you wrote that you don't know if the fact that SetEnvironmentVariable, unlike_putenv(), manipulates the actual process environment variable matters in practice. I have written code where I saw that prepending a directory to PATH using _putenv() works, but using SetEnvironmentVariable doesn't. So apparently it can make a difference. – Alan Oct 02 '17 at 18:36
  • 1
    Unfortunately `putenv` does not appear to be correct so will not work with `const char *`. `setenv` however is and will. – Catskul Mar 06 '19 at 06:11
  • Does not this work just when the process is in mode "run as admin"? And if yes is there any method that works for users with non-admin rights? – CJ_Notned Aug 17 '22 at 11:43
  • 1
    No, it should work even not as admin. But I assume if you want to set an env var system-wide (not just current process and descendants) you should use some other facility, and that one might need admin rights. – alamar Aug 17 '22 at 12:54
8

There's also setenv, which is slightly more flexible than putenv, in that setenv checks to see whether the environment variable is already set and won't overwrite it, if you set the "overwrite" argument indicating that you don't want to overwrite it, and also in that the name and value are separate arguments to setenv:

NAME
        setenv - change or add an environment variable
SYNOPSIS
       #include <stdlib.h>

       int setenv(const char *name, const char *value, int overwrite);

       int unsetenv(const char *name);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       setenv(), unsetenv():
           _POSIX_C_SOURCE >= 200112L
               || /* Glibc versions <= 2.19: */ _BSD_SOURCE
DESCRIPTION
       The setenv() function adds the variable name to the environment with
       the value value, if name does not already exist.  If name does exist
       in the environment, then its value is changed to value if overwrite
       is nonzero; if overwrite is zero, then the value of name is not
       changed (and setenv() returns a success status).  This function makes
       copies of the strings pointed to by name and value (by contrast with
       putenv(3)).

       The unsetenv() function deletes the variable name from the
       environment.  If name does not exist in the environment, then the
       function succeeds, and the environment is unchanged.

I'm not saying either is better or worse than the other; it just depends on your application.

See http://man7.org/linux/man-pages/man3/setenv.3.html

MarkR
  • 166
  • 1
  • 8
3

I'm not positive environment variables are what you need, since they aren't going to be used outside of this run of the program. No need to engage the OS.

You might be better off having a singleton class or a namespace that holds all these values, and initialize them when you start the program.

V-R
  • 1,309
  • 16
  • 32
JohnMcG
  • 8,709
  • 6
  • 42
  • 49
  • 1
    They will only be visible to child processes, and putenv() usually doesn't need to talk to the OS at all. – RBerteig May 22 '09 at 20:23
  • I do not agree with the answer. Sometimes you need to load third party components via DLLs that use environment variables. It is sometimes required to set. – AlexF Jul 11 '23 at 11:45
0
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

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

    char *var, *value;
    if (argc == 1 || argc > 3) {
        fprintf(stderr, "usage:environ variables \n");
        exit(0);
    }
    var = argv[1];
    value = getenv(var);
    //---------------------------------------
    if (value) {
        printf("variable %s has value %s \n", var, value);
    }
    else
        printf("variable %s has no value \n", var);
    //----------------------------------------
    if (argc == 3) {
        char* string;
        value = argv[2];
        string = malloc(strlen(var) + strlen(value) + 2);
        if (!string) {
            fprintf(stderr, "out of memory \n");
            exit(1);
        }
        strcpy(string, var);
        strcat(string, "=");
        strcat(string, value);
        printf("calling putenv with: %s \n", string);
        if (putenv(string) != 0) {
            fprintf(stderr, "putenv failed\n");
            free(string);
            exit(1);
        }
        value = getenv(var);
        if (value)
            printf("New value of %s is %s \n", var, value);
        else
            printf("New value of %s is null??\n", var);
    }
    exit(0);

} //----main
# commands to execure on linux   
# compile:
$ gcc -o myfile myfile.c

# run:
$./myfile xyz
$./myfile abc
$./myfile pqr
Marek R
  • 32,568
  • 6
  • 55
  • 140
  • I expect the answer to consist of (1) an include file and (2) a single line of code. And maybe a library I must link with. – notlesh Apr 30 '14 at 19:20
  • 3
    notlesh, why ? Also the compile instructions are right there. Why add more files? I don't get why this is voted down. – Owl May 25 '17 at 12:08
  • 3
    It's good practice on Stack Overflow to add an explanation as to why your solution should work. For more information read [How To Answer](//stackoverflow.com/help/how-to-answer). – Samuel Liew Apr 11 '18 at 23:07