newprint
newprint

Reputation: 7136

Pointer Arithmetic question

Could someone plz explain to me, what is happening in the following two lines of code ? Assuming that we are working on 32-bit machine

p - is pointer

(*(long *)((char **)(p) - 1))
(*(int *)((int)(p) - 4))

The only thing I understood, is that *(long *) converts "something" to pointer of type long and then deref. to get the value.

Thanks !

Upvotes: 1

Views: 280

Answers (5)

Alam
Alam

Reputation: 1596

Considering p is a pointer to two dimensional array for .eg

int a[][5] = {10,20,30,40,50,11,21,31,41,51,12,22,32,42,52,13,23,33,43,53,14,24,34,44,54};
int (*p)[5] = a;

Now for sake of simplicity we assume address of a[0][0] as 1000

Now lets evaluate (*(long *)((char **)(p) + 1));

  1. (char **)(p) will give you address of a[0][0] >>>> i.e 1000
  2. (char **)(p) + 1 will add sizeof int to your address >>>> i.e 1004
  3. (*(long *)) will get the value at address 1004 which is 20 in our example

(*(long *)((char **)(p) + 1)); will evaluate to 20 in our case

Upvotes: 1

Abyx
Abyx

Reputation: 12918

First gets long before p.
For x32 sizeof(char*) == sizeof(long), so (long*)(char*) is (long)
So it's simply *( (long*)p - 1 ) or ((long*)p)[-1]

The second line does the same, but it yields int instead of long. (long*)p - 1 is the same address as (int)p - 4, because sizeof(long) == 4.

Upvotes: 1

fazo
fazo

Reputation: 1827

1: ((char **)(p) - 1): cast p to point to array of arrays of chars and subtract (so it's now like &p[-1])

(long *): cast it to pointer to long's, and last take long from that address.

2: ((int)(p) - 4): cast p to int and subtract 4

(int *): cast it to point to array of int's, and take int from that address

Upvotes: 1

wrosecrans
wrosecrans

Reputation: 1085

(*(long *)((char **)(p) - 1))

Start with the pointer p. Cast it to the type (char **). Subtract one from it. Cast the result to the type (long *) and then dereference the result. In other words, shift the pointer by one byte, and get the value of the long stored at that address. This operation may well be broken on some platforms, especially depending on the type of p.

(*(int *)((int)(p) - 4))

Start with the pointer p. Cast it to an int. Subtract 4. Cast it to an (int*), and dereference the result. Now, instead of doing normal pointer arithmetic, you are directly fiddling with the pointer value as an integer, shifting it by four, and reading the int that the result points to. This operation will also be broken on some systems.

I think I managed to parse that without getting lost in the parens. In any case, don't do this. It's pathological. There might be some weird embedded development task where you think something like this is a good idea. If so, never admit to having done it. Blame it on somebody else if it is discovered.

For example, with the second example, with p as an int*, and on a system with 8 bit chars and 32 bit ints, you are basically accomplishing *(p-1)

OTOH, on a machine with a 16 bit int, you are doing *(p-2), and on a machine with a 64 bit int, you are doing *(p-0.5), which isn't sensible, and may well crash while just complaining about an unaligned memory access. (And it deserves to crash.) Use pointers that actually point at the right type, and you should never have a reason to do this sort of nonsense.

Upvotes: 1

Bill Bingham
Bill Bingham

Reputation: 244

    (*(long *)((char **)(p) - 1))

    Looks like getting the length of some kind of length byte character array 
that was passed by reference. But that is just first glance..

    (p) = some object

    (char **) casts some object to the address of the address of a character, which is a 32bit value sizeof(char**)

    -1 gets the 32bits in memory prior to (char **)(p)
    *(long*) does what you thought, takes that 32bits, casts it as a long *, and dereferences it.
    So there is a record in memory like: 

    struct {long * n; char ** s;  } 
    similiar to what happens in parameter passing.

(*(int *)((int)(p) - 4))

this one is uglier. Some object p is cast to an int, let's just hope sizeof(int) is 32, so it may be an address, subtract 4 from it (addresses are still counting bytes, 4 bytes is 32 bits) cast that as a pointer to int, and dereference it.

For extra credit compare it to: *((int *)((int)(p)) - 1)

Upvotes: 1

Related Questions