# Understanding some code

## 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 on other sites
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 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 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 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 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 on other sites
Quote:
 Original post by KulSeranptr->whatever == "blah"

That doesn't do what you want.

##### Share on other sites
Quote:
Original post by DevFred
Quote:
 Original post by KulSeranptr->whatever == "blah"

That doesn't do what you want.

It could...

##### Share on other sites
Quote:
 Original post by EeyoreHey 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 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 on other sites
Quote:
 Original post by EeyoreHey all, I just wanted some help understanding some code.const char *cmd = argv[0] && *argv[0] ? argv[0] : "git-help";

This is logically equivalent to:

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

That is because of the early-out of the && operator. If the left condition fails, it will never check/execute what's on the right side.

##### Share on other sites
NULL is typically used with pointer values. As such, I would use the NUL character for the second condition:
const char *cmd = "git-help";if (argv[0] != NULL){	if (*argv[0] != '\0')	{		cmd = argv[0];	}}

##### Share on other sites
Quote:
 Original post by rip-offNULL is typically used with pointer values. As such, I would use the NUL character for the second condition:

Just an addendum: "Should I use NULL or 0?"

##### Share on other sites
Quote:
 Original post by rip-offNULL is typically used with pointer values. As such, I would use the NUL character for the second condition.

You're absolutely right. However, I was just demonstrating what the logic behind the original and somewhat hard-to-understand statement was, by translating it to an equivalent if/else block. And the original code does in fact check that both argv[0] && *argv[0] have non-0 values, which is equivalent to != NULL if NULL is defined as 0. :)

##### Share on other sites
NULL may be 0, but my point is about intent. When I see something compared with NULL, I'm going to assume that the other thing is a pointer. If I see it compared with '\0' then my assumption is that the other thing is a character. That is all [smile]

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
628301
• Total Posts
2981914

• 10
• 11
• 11
• 10
• 10