Set local environment variables in C++
Asked Answered
C

4

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

Cockle answered 22/5, 2009 at 19:12 Comment(0)
W
67
NAME

       putenv - change or add an environment variable

SYNOPSIS

       #include <stdlib.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.

Weixel answered 22/5, 2009 at 19:14 Comment(14)
Note to questioner - putenv is also supported in Win32.Cage
Can we please use proper C++ header names? <cstdlib> is appropriate (yeah, I know...it's a hangup of mine).Vasyuta
It is C as a Lord God intended.Weixel
stlib.h is a proper C header file - the question is tagged as CCage
Are you sure that the change isn't global on Windows ?Scintillation
"Sets the contents of the specified environment variable for the current process."Weixel
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.Nightfall
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).Counterpane
SetEnvironmentVariable is certainly not an ugly function name; it's much more descriptive than putenv.Cynical
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.Prehensible
@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.Latterly
Unfortunately putenv does not appear to be correct so will not work with const char *. setenv however is and will.Biggerstaff
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?Sigma
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.Weixel
M
9

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

Mihalco answered 14/5, 2020 at 19:46 Comment(1)
It is more practical, it avoid to deal with a 'non const' char* as a parameter.Pernicious
M
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.

Mouth answered 22/5, 2009 at 19:53 Comment(2)
They will only be visible to child processes, and putenv() usually doesn't need to talk to the OS at all.Nightfall
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.Plauen
P
1
#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
Prompt answered 27/4, 2011 at 11:25 Comment(4)
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.Diskin
notlesh, why ? Also the compile instructions are right there. Why add more files? I don't get why this is voted down.Andes
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.Topazolite
The tittle mention C++ not C.Replay

© 2022 - 2024 — McMap. All rights reserved.