5

In my code I'm using the following:

putenv("TZ=UTC");
tzset();

to set the timezone.

Declaration of putenv() (this answer recommended it to set the environment variable):

int putenv(char *string);

The buildsystem I'm using sets compiler flags -Wall -Wextra -Werror -std=c++0x and due to that I'm getting the error:

timeGateway.cpp:80:18: error: ISO C++ forbids converting a string constant to 'char*' [-Werror=write-strings]
   putenv("TZ=UTC");
                  ^

I know that this error can be suppressed by using:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wwrite-strings"
  putenv("TZ=UTC");
#pragma GCC diagnostic pop

But this is very ugly.

My question: what is a proper way to set an environment variable in C++?

Community
  • 1
  • 1
lewiatan
  • 1,126
  • 2
  • 21
  • 37
  • Read the man page of [`putenv`](http://linux.die.net/man/3/putenv) carefully, it has some important stuff there! – hyde Aug 17 '16 at 10:26

2 Answers2

8

The string literal is const, its type is const char[] (for "TZ=UTC" it'll be const char[7], including the trailing null character '\0'), which can't be assigned directly to a (non-const) char* from C++11.

You could construct a new char array for it.

char str[] = "TZ=UTC"; // initialize a char array, which will contain a copy of the string "TZ=UTC"
putenv(str);
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • Deleted my obviously faulty answer (my apologies). If the answer by @songyuanyao works, please mark it as the answer. – Peter K Aug 17 '16 at 10:09
4

putenv normally allows the string to be changed after the call to putenv and that actually automatically changes the environment. That is the reason why the prototype declares a char * instead of a const char *, but the system will not change the passed string.

So this is one of the rare correct use cases for a const cast:

putenv(const_cast<char *>("TZ=UTC"));

Alternatively, you could use setenv that takes const char * parameters:

setenv("TZ", "UTC", 1);
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • This is a prime example of why `const_cast` exists (to work around poor APIs as long as you absolutely _know_ it won't try to modify the value) and IMO presents better/more direct solutions than requiring an intermediate non-`const` variable. +1 – underscore_d Aug 17 '16 at 10:45
  • "That is the reason why the prototype declares a `char *` instead of a `const char *`". This doesn't make sense to me, `putenv()` still could declare `const char*` as parameter's type if it won't modify on it, since `char*` could be implicit converted to `const char*`, no troubles would be bought to the client code. – songyuanyao Aug 19 '16 at 08:29
  • @songyuanyao: to later allow changes to be correctly processed, the parameter must be cast to `char *` somewhere. If not the compiler could cache the first read value. – Serge Ballesta Aug 19 '16 at 08:45
  • @SergeBallesta Cast, you meant in `putenv`, or client code? In client code, if it's expected to change the string later, a char array should be used (and passed to `putenv`) at first. – songyuanyao Aug 19 '16 at 08:52
  • @songyuanyao: I meant in `putenv` code or more precisely in the `environment` management code for which `putenv` is just an interface. In that management part, the parameter is indeed a `char *` – Serge Ballesta Aug 19 '16 at 09:00
  • @SergeBallesta If it will be modified by `putenv` or other environment relevant code, isn't it a dangerous thing to pass a string literal to it? (Even it's safe for current OP's code.) – songyuanyao Aug 19 '16 at 09:03
  • @songyuanyao: the environment code does not modify it. It just allows caller to modify it and guarantees that those modification will be observed. If the caller does not modify it it is perfectly safe to use a litteral. But to allow modification to be reflected, the environment code cannot refer to it as a `const`. – Serge Ballesta Aug 19 '16 at 09:06
  • @SergeBallesta I got your point. If it's `const char*`, any later modification won't be observed by environment code, because `const char*` might be cached. Alright. – songyuanyao Aug 19 '16 at 11:25