You are not logged in.

#1 2016-03-31 11:38:48

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,530
Website

[SOLVED] argc argv inverted, still works?

I just had a github issue reported on one of my projects which I just rewrote yesterday.  Apparently I was a bit tired while working on it, and I swapped many uses of the main function arguments 'argc' and 'argv' (but not in the main function declaration).  Despite the clear error which should have completely prevented the program from working, everything worked fine.  I replicated the oddity with the following minimal code:

#include <stdlib.h>
#include <stdio.h>

int main(int argc, const char **argv) {
	if (argc < 3) return 1;
	printf("%s %s\n",argc[argv-2],argc[argv-1]);
	return 0;
}

As seen in the printf line, argc and argv are clearly swapped.  While subtracting a number from a pointer can work, treating an integer as an array should definitely fail.  In any case, this should most definitely not properly print the last two command line arguments ... but it does.

There are no errors or warnings during compilation, even with -Wpedantic, and the resulting program does exactly what was intended though clearly not properly coded.

Is this a common enough typo that gcc is just being a bit too much of a nanny and fixing it for me?  If so, why is it not at least giving a warning?  How else might this code manage to get the intended result with the wrong code?

EDIT:  I've found that using the argv-2, argv-1 values as indices to any int (not int array!) seem to work the same way:

#include <stdlib.h>
#include <stdio.h>

int main(int argc, const char **argv) {
	int b = 3;
	if (argc < 3) return 1;
	printf("%s %s\n", b[argv-2], b[argv-1]);
	return 0;
}

This also prints the last two command line parameters.  On the suspicion that this might be some lucky coincidence of the stack addresses, I added various other variable declarations around 'b' and also moved b's declaration outside of the main function, but in every case the command line parameters were still "properly" printed.

EDIT 2: through various other permutations I've found that the compiler seems to *silently* fix any inversion of the form I[S-C] to S[I-C] where S is a char **, I is an int, and C is a numerical constant (C can also be an int apparently).  Is this documented somewhere that I'm not finding?  And why wouldn't there be a warning at least?

----

*Headdesk*  No inversions need be "fixed": the printf function with "%s" looks for a memory address for a string.  Lets say our char ** had address 0x12344321 and the int we treat as an array was set to 3 and the constant was -1.  Normally we'd put s[i-1] which sould be interpretted as 0x12344321 + (3 - 1) which would give an address of 0x12344323 and the value stored there is the pointer to the start of the character data we want to use.  But if we put i[s-1] in our code instead, now it is interpreted as the value of the integer 3 offset by an index of (0x12344321-1) so we again get a result of 0x12344323 which is the memory address of the same pointer to the same block of character data.  I gather this is why it works.

But the question remains why the compiler allows an integer to be given a [offset].


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#2 2016-03-31 12:14:30

mauritiusdadd
Member
From: Benevento, Italy
Registered: 2013-10-27
Posts: 776

Re: [SOLVED] argc argv inverted, still works?

I think it is related to how the operator [] is defined: http://stackoverflow.com/questions/2961 … -work-in-c.
So the following statements should be equivalent: argv[argc - 1] = *(argv + argc - 1) = *(argc + argv - 1)  = argc[argv - 1]

edit: typo

Last edited by mauritiusdadd (2016-03-31 14:57:45)


About me - github

-- When you have eliminated the impossible, whatever remains, however improbable, must be the truth -- Spock | Sherlock Holmes

Offline

#3 2016-03-31 12:16:59

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,530
Website

Re: [SOLVED] argc argv inverted, still works?

Ha, thanks, you were posting at the same time as my last edit where I arrived at the same conclusion.  But I'm still not sure why we don't get errors or at least a warning about treating an integer as an array.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#4 2016-03-31 12:17:01

Trent
Member
From: Baltimore, MD (US)
Registered: 2009-04-16
Posts: 990

Re: [SOLVED] argc argv inverted, still works?

This is an oddity of how array indexing is defined in C. Commutativity of the [] operator in C

Basically, a[ i] is equivalent to *(a + i), so argc[argv + 1] is the same as *(argc + argv + 1) and since addition (even pointer addition) is commutative, it's the same as if you wrote argv[argc + 1] like you obviously meant to do.

So there's no warning because it's not wrong: doesn't violate any constraints, obeys the type system, and has a meaningful interpretation that happens to be what you wanted to do in the first place.

As you might expect, this kind of thing features mostly in intentionally obfuscated code, but this is the first time I've seen someone do it by accident smile

Edit for phrasing

Last edited by Trent (2016-03-31 12:18:47)

Offline

Board footer

Powered by FluxBB