Jump to content
  • Advertisement
Sign in to follow this  
Stormtrooper

Understanding some code

This topic is 3498 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey all, I just wanted some help understanding some code.
const char *cmd = argv[0] && *argv[0] ? argv[0] : "git-help";
Okay, I understand what it is doing...I just don't understand why they are doing it. The && will return true if argv[0] and *argv[0] are non-zero. If it is true, it will return argv if it is false it will return git-help....right?

Share this post


Link to post
Share on other sites
Advertisement
It checks if there is a non-empty string in argv[0]. Typically there is. However, there are situations where there might not be (e.g. a careless call to an exec function). In this case, the default value used is "git-help".

Why? Paranoia [smile]

Share this post


Link to post
Share on other sites
argv[0] is string containing the name of executable which was used to run this application.

Consider:
const char * s = 0;
const char * s = "";
Both of those can be considered invalid. One is not allocated, the other is empty string.

In original statement, cmd will hold either valid string (non-null, non-empty) or "git-help".

I honestly don't remember ever checking for that condition, but perhaps it is sometimes possible for argv[0] to contain invalid filename.

Share this post


Link to post
Share on other sites
I *think* argv[0] just contains the command that was used to invoke the executable. This does not necessarily have to be the actual path of the executable ... for instance, on Linux it could just as well be an alias or a soft link.

Share this post


Link to post
Share on other sites
really though, they are using the early-out mechanism of &&.
Consider

T *ptr = 0;
if ( ptr && ptr->whatever == "blah" )

First it checks (ptr != NULL). If ptr isn't NULL, it then checks ptr->whatever == "blah".
If ptr is NULL, it early outs and just returns false for the whole statement whout executing anything on the right.

Share this post


Link to post
Share on other sites
Quote:
const char *cmd = argv[0] && *argv[0] ? argv[0] : "git-help";


In C/C++, the precedence of && is so that the above if the equivalent of ...

const char *cmd = (argv[0] && *argv[0]) ? argv[0] : "git-help";




... or ...

const char *cmd;
if (argv [0] && *argv [0]) {
cmd = argv [0];
} else {
cmd = "git-help";
}



Precedence may change in other languages, like PHP, where you should always underline your intention with brackets when using the ternary operator.

As KulSeran pointed out, the author is making use of the shortcircuit behaviour of the logical && operator, which means that in (A&&B) B is only queried ("executed") if A!=0, or the other way, if A is zero, than it is clear that the whole statement will be zero, and the evaluation of B is skipped.

Btw, in Bash, those short circuits also exist, so "make && make install" means, that "make install" is only executed if "make" returns 0 (where 0 in nix means success, as compared to !=0 in C/C++). This is very usefull if you distaste IDEs for your daily dev ("make && ./my-binary").

(Anecdote:)
Actually, this can yield bad performance on modern CPU, as that short circuit behaviour yields a branch, and with modern techniques like code prefetching, speculative execution + co., the use of that operator can cause prediction misses (which means: if a miss is determined by the CPU, code that already has been executed speculatively is then considered invalid, and the correct code has to be "re-executed").

If, and only, in the expression (A&&B), B is independent of the value of A (not the case in your example), and you can ensure that the relevant bits of A and B are at the same position (for boolean expressions generally the 0th bit), you can replace (A&&B) with (A&B), same for (A||B) --> (A|B). Those bitwise operators have to execute both A and B anyways, and so no branch is produced, leading to a branchfree epression.

Google for Agner Fog and the Intel Optimization Guides for more of that stuff :)


(Anecdote2:)
In Unix/GNU/Linux environments, it is often common that several links to the same binary exist in /bin, /usr/bin, and fellows. For example, the program "[" is the same binary as "test", but the behaviour slightly changes. The actual binary determines that by checking argv[0]. Cool.

Share this post


Link to post
Share on other sites
Quote:
Original post by Eeyore
Hey all, I just wanted some help understanding some code.

const char *cmd = argv[0] && *argv[0] ? argv[0] : "git-help";


Okay, I understand what it is doing...I just don't understand why they are doing it.

The && will return true if argv[0] and *argv[0] are non-zero. If it is true, it will return argv if it is false it will return git-help....right?


It's important to note that if "argv[0]" evaluates to false, it will never even do the "&& *argv[0]" but will still render the total conditional to be false, returning "git-help". This is good, because if argv[0] was 0, you wouldn't even be able to read from that memory location in most operating systems.

Cheers
-Scott

Share this post


Link to post
Share on other sites
[sarcasm]
DevFred, how do you know that type T is not supposed to have a member named whatever that is a std::string that i want to compare to "blah".
[/sarcasm]
Yeah, I prolly should a have made a more complete example.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!