[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

C's pointer arithmetic (Was Re: Setting effective UID for a shell script)



>>>    execv( argv[1], argv + sizeof( argv[1] ) );
>>  Could you explain this? Why would this line be *more* correct than the
precedent?

> The second version makes the pointer arithmetic explicit and has the
> correct type for the second argument.  The first involves an implicit
> cast from char* to char**.
 Correct.

[snip]
> cast takes place from char* to char**.  Now it so happens that argv[2]
> is the beginning of an array pointers which is just argv with the
> first two items in it cut off, which is the array of arguments I want
> the pass to execv.  I could make the cast explicit, but gcc is happy
> to do it implicitly, so I let it.
 gcc -Wall -ansi -pedantic rules :)

execv (argv[1], (char**) argv[2]);

> Moreover, argv + sizeof (argv[1]) is equal to argv[4] (as sizeof (char*) =
4) ...

> No.  If that were so then you could not access the list of arguments
> to a main function as argv[0], argv[1], argv[2] etc.  The compiler
> knows that the type of argv is char**, or char*[], an array of
> pointers to chars, and it knows that sizeof( char* ) is 4 (on the
> platforms we're talking about).  It is almost an axiom that
> argv[1] == argv[0] + sizeof( argv[0] ), since this is the address of
> the next element in the array.  So argv[4] = argv + 4*sizeof( argv[1]).

Wrong. We are talking about pointers, not about integers nor unsigned.
When you write
 argv + 1, the compiler will understand : compute the address
of argv, and add one time the size of the type which is pointed by argv.
I remember to you that argv[1] = argv + 1. Brackets are only syntactic
sugar, which allows us not seeing we are dealing with pointer arithmetic.

Examples :
--
corwin@dagobah:/tmp/test$ cat main.cc
#include <iostream>

int
main (int argc, char** argv)
{
  std::cout << "argv = " << argv << std::endl
            << "sizeof (argv[1]) = " <<  sizeof (argv[1]) << std::endl
            << "content = " << *(argv + sizeof (argv[1])) << std::endl;
  return 0;
}
[1]+  Done                    emacs main.cc
corwin@dagobah:/tmp/test$ g++ -Wall -ansi -pedantic --static main.cc
corwin@dagobah:/tmp/test$ ./a.out "first" "second" "third" "lost"
argv = 0xbffffd04
sizeof (argv[1]) = 4
content = lost
corwin@dagobah:/tmp/test$
--
leslie% cat test2.cc
#include <iostream>

int
main (int argc, char** argv)
{
  std::cout << "argv = " << argv << std::endl
            << "argv[1] = " << &(argv[1]) << std::endl
            << "argv + 1 = " << argv + 1 << std:: endl
            << "argv + sizeof (char*) = " << argv + sizeof (char*) <<
std::endl;
  return 0;
}
leslie% g++ -Wall -ansi -pedantic test2.cc
leslie% ./a.out "one"
argv = 0xbffffbe4
argv[1] = 0xbffffbe8
argv + 1 = 0xbffffbe8
argv + sizeof (char*) = 0xbffffbf4
leslie%
--

That's why Nicos Gollan was perfectly right, if we were on a 64 bits
architecture,
we would have argv + sizeof (char*) = argv + 8 = argv[8]

Regards,

Perceval.


-- 
To UNSUBSCRIBE, email to debian-user-request@lists.debian.org 
with a subject of "unsubscribe". Trouble? Contact listmaster@lists.debian.org



Reply to: