Why does getenv() work backwards?

P

Protoman

Why does getenv work backwards? When I'm testing an env variable, I
have to test if its NOT equal to, rather than equal to, to get the
desired result. As evidenced by this simple piece of code:

#include <iostream>
#include <cstdlib>
using namespace std;

const char* cpu=getenv("PROCESSOR_ARCHITECTURE");

int main()
{
if(cpu!="x86")
cout << "Valid " << endl;
else
cout << "Invalid " << endl;
system("PAUSE");
return 0;
}

If I use if(cpu=="x86"), I get invalid, which is wrong, but if I use
if(cpu!="x86), I get valid, which is correct. It's like something is
backwards here, either with getenv() or WinXP itself. What's going on
here?
 
D

danda

#include <iostream>
#include <cstdlib>
using namespace std;

const char* cpu=getenv("PROCESSOR_ARCHITECTURE");

int main()
{
if(cpu!="x86") // this is the problem, don't use != to compare
cout << "Valid " << endl;
else
cout << "Invalid " << endl;
system("PAUSE");
return 0;

}
 
M

Matthias Kaeppler

Protoman said:
Why does getenv work backwards? When I'm testing an env variable, I
have to test if its NOT equal to, rather than equal to, to get the
desired result. As evidenced by this simple piece of code:

#include <iostream>
#include <cstdlib>
using namespace std;

const char* cpu=getenv("PROCESSOR_ARCHITECTURE");

int main()
{
if(cpu!="x86")
cout << "Valid " << endl;
else
cout << "Invalid " << endl;
system("PAUSE");
return 0;
}

If I use if(cpu=="x86"), I get invalid, which is wrong, but if I use
if(cpu!="x86), I get valid, which is correct. It's like something is
backwards here, either with getenv() or WinXP itself. What's going on
here?

This effect is just random I guess. What you're doing is comparing two
pointers, that is, two addresses, and not the character sequences
they're pointing to.
To compare two arrays of char, use strcmp(), or better yet, use
std::string, that's what we have it for.

Regards,
Matthias
 
P

Protoman

Matthias said:
This effect is just random I guess. What you're doing is comparing two
pointers, that is, two addresses, and not the character sequences
they're pointing to.
To compare two arrays of char, use strcmp(), or better yet, use
std::string, that's what we have it for.

Regards,
Matthias

Still, I wonder... Guess I'll just succom to having to think backwards
with getenv(). And is there anyway I can make sure the program will
only work if the machine its running on has the same env variable
values as the machine its compiled on?
 
J

Jacek Dziedzic

Protoman said:
Still, I wonder... Guess I'll just succom to having to think backwards
with getenv().

It doesn't work backwards. It's an illusion you get by trying
to compare char arrays in a way they cannot be compared. Use strcmp().
And is there anyway I can make sure the program will
only work if the machine its running on has the same env variable
values as the machine its compiled on?

If there is, it's not by comparing pointers and inverting
the result (what you're currently doing).

HTH,
- J.
 
G

Greg

Protoman said:
Why does getenv work backwards? When I'm testing an env variable, I
have to test if its NOT equal to, rather than equal to, to get the
desired result. As evidenced by this simple piece of code:

#include <iostream>
#include <cstdlib>
using namespace std;

const char* cpu=getenv("PROCESSOR_ARCHITECTURE");

Since this is a C++ group let's declare cpu like this:

const std::string cpu( getenv("PROCESSOR_ARCHITECTURE"));
int main()
{
if(cpu!="x86")
cout << "Valid " << endl;
else
cout << "Invalid " << endl;
system("PAUSE");
return 0;
}

If I use if(cpu=="x86"), I get invalid, which is wrong, but if I use
if(cpu!="x86), I get valid, which is correct. It's like something is
backwards here, either with getenv() or WinXP itself. What's going on
here?

With cpu now a std::string the comparison with "x86" will work as you
think it should, meaning that the strings themselves are being
compared, not their addresses. This also means that the if-statement
logic needs to be put back the way it was originally:

int main()
{
if ( cpu=="x86")
cout << "Valid\n";
else
cout << "Invalid \n";
system("PAUSE");
return 0;
}

Greg
 
K

Karl Heinz Buchegger

Protoman said:
Still, I wonder... Guess I'll just succom to having to think backwards
with getenv(). And is there anyway I can make sure the program will
only work if the machine its running on has the same env variable
values as the machine its compiled on?

What output would you expect in the following:

#include <iostream>

int main()
{
int* i = new int
int* j = new int;

*i = 5;
*j = 5;

if( i == j )
cout << "They are equal\n";
else
cout << "They are not equal\n";

delete i;
delete j;
}

You have done exactly that in your program.
To fix it, you changed

if( i == j )

to

if( i != j )

and are now speculating about some backwards logic.
But the problem is something completely different:
instead of comparing values

if( *i == *j )

you compared pointers

if( i == j )

The only difference is, that with C-style strings you
can't use == for comparing the strings, but have to
use strcmp to do exactly that: compare if 2 C-style
strings compare equal by value.
 
M

Michiel.Salters

Greg said:
Protoman wrote:

Since this is a C++ group let's declare cpu like this:

const std::string cpu( getenv("PROCESSOR_ARCHITECTURE"));

We really should something like map<string,string> env;' in std,
so we'd simply say if( std::env["PROCESSOR_ARCHITECTURE"]=="x86")

Of course, the return type should be a bit different, else your
assignments
to env["X"] won't end up calling setenv( ).

HTH,
Michiel Salters
 
M

Marcus Kwok

Protoman said:
This is SO confusing

*What* is so confusing? Please include context in your replies

Run this program and see if you understand what is happening:


#include <iostream>
#include <cstring>

int main()
{
char* a = "hello";
char* b = "hello";

if (a == b)
std::cout << "pointers: equal\n";
else
std::cout << "pointers: not equal\n";


if (std::strcmp(a, b) == 0)
std::cout << "strcmp: equal\n";
else
std::cout << "strcmp: not equal\n";


return 0;
}
 
R

Ron House

Protoman said:
This is SO confusing

It is actually very simple, but you lack a few facts:

1) a C-style string is, grammatically, just an array of char.

2) In C/C++, you can NOT compare entire arrays for equality or inequality.

therefore:

3) You can NOT compare c-style strings for equality or inequality.

Now:

4) writing the name of any array in an r-value context (such as either
side of == or !=), in C/C++, yields, not the array, but rather the
address of the array.

therefore:

5) writing "if (cpu == "x86")" does NOT compare the arrays, but rather
it compares the address of the array cpu with the address of the spot
where the string literal "x86" is stored; these will NEVER be the same,
whether cpu contains "x86" or not, so any hope you have of simple
reversing the sense of the test will be in vain.

but luckily:

6) the designers of C wanted you to be able to compare strings, so

7) they invented the strcmp function, yielding an int that is <, ==, or
> zero depending on whether the first string is before, the same as, or
after the second alphabetically.

therefore

8) you should write "if (strcmp(cpu, "x86") == 0)" to test for equality.
 
M

Michiel.Salters

Marcus said:
int main()
{
char* a = "hello";
char* b = "hello";

if (a == b)
std::cout << "pointers: equal\n";
else
std::cout << "pointers: not equal\n";


if (std::strcmp(a, b) == 0)
std::cout << "strcmp: equal\n";
else
std::cout << "strcmp: not equal\n";
}

Bad example - a might be equal to b, or not. Besides, it really should
be const char*. If you'd wrote char a[] and char b[], the example would
be predictable, and you wouldn't need const.

Michiel.
 
K

Karl Heinz Buchegger

Marcus said:
*What* is so confusing? Please include context in your replies

Run this program and see if you understand what is happening:

#include <iostream>
#include <cstring>

int main()
{
char* a = "hello";
char* b = "hello";

if (a == b)
std::cout << "pointers: equal\n";
else
std::cout << "pointers: not equal\n";

if (std::strcmp(a, b) == 0)
std::cout << "strcmp: equal\n";
else
std::cout << "strcmp: not equal\n";

return 0;
}

But beware:
Actually that program 'might' come up with Protoman's
expected output. It all depends on the compiler if it
creates 2 string literals "hello" or just one, setting
a and b to the same value.
 
M

Mike Smith

Protoman said:
This is SO confusing

<sigh> Your problem is not with getenv(). Your problem is that you are
comparing pointers when you think you are comparing strings.

char const *a = "Hello!";
char const *b = "Hello!";
if (a == b) printf("Equal!");

In the code fragment above, the printf() will never get called, because
the values of a and b are different, even though the strings they point
to are the same.

char const *a = "Hello!";
char const *b = "Hello!";
if (!strcmp(a, b)) printf("Equal!");

*This* will work because the library function strcmp() compares, not the
pointer values themselves, but the character strings that the pointers
point to.
 
A

Andre Kostur

<sigh> Your problem is not with getenv(). Your problem is that you are
comparing pointers when you think you are comparing strings.

char const *a = "Hello!";
char const *b = "Hello!";
if (a == b) printf("Equal!");

In the code fragment above, the printf() will never get called, because
the values of a and b are different, even though the strings they point
to are the same.

Actually in this case it might. The compiler may realize that those two
are the same string literal and only make one copy of it. A better example
would be:

char a[] = "Hello!";
char b[] = "Hello!";

This would force a and b to be at different memory locations.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top