Understanding some code

Started by
13 comments, last by rip-off 15 years, 3 months ago
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?
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]
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.
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.
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.
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.
Quote:Original post by KulSeran
ptr->whatever == "blah"

That doesn't do what you want.
Quote:Original post by DevFred
Quote:Original post by KulSeran
ptr->whatever == "blah"

That doesn't do what you want.


It could...
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
[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.

This topic is closed to new replies.

Advertisement