views:

148

answers:

3

Incase of pointer arithmetic, are the integers automatically converted to their signed variants? If yes, why?

Suppose I do

int *pointer; 
int *pointerdiff;
unsigned int uiVal = -1;

pointerdiff = pointer + uiVal // Pointer will contain valid address here.

where pointer is a pointer to int and uiVal is initialized to -1, then I find that the address in pointers get decremented by 4. Why is the unsigned value of -1 not considered here?

+2  A: 

Yes, integer operands are promoted. But that doesn't matter here. uiVal cannot be -1 if it's of unsigned type. Probably you did

unsigned int uiVal = -1;
pointer + uiVal ...

But that will do the same as

pointer + UINT_MAX ...

And this is likely to cause undefined behavior if the address range the pointer can hold can't cope with this addition. The Standard says at 5.7/4

For the purposes of these operators, a pointer to a nonarray object behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.

When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, [...]. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

That is, if the result pointer does not lie in the same array or one past the end, or if it does but did so by overflow, behavior is undefined.

Johannes Schaub - litb
But, the point is, it is not giving me undefined behaviour. Rather it is behaving exactly like a -1 has been done. This is what surprises me.
Jay
@Jay, saying that behavior is undefined means that anything can happen, including that you will always get the same behavior. It doesn't necessarily mean that you get a segfault. On a 64bit platform with 32bit unsigned int, you are likely to get different behavior.
Johannes Schaub - litb
A: 

I think right operand is casted to ptrdiff_t type, which seems to be signed.

el.pescado
+6  A: 

It looks like your pointer is overflowing.

Let's do some maths. Say you're on a 32-bit machine, and your pointer is initialised to 0x 12 34 56 78. We then initialise an unsigned int variable to -1, which is 0x FF FF FF FF. Because it's an unsigned integer, the -1 is overflowing and actually represents 4 294 967 295.

Your pointer is to an integer (int*), so each increment actually increments the address by sizeof int, which is 4 on a standard x86 machine. So we're actually adding 0x 03 FF FF FF FC (which is 0x FF FF FF FF * 4).

Now let's add the two together.

  0x 00 12 34 56 78
+ 0x 03 FF FF FF FC
-------------------
  0x 04 12 34 56 74

Of course, this overflows, because we now have a 40-bit value, and a pointer is 32 bits and can only hold that much information. We therefore lose the 04 at the start. This results in 0x 12 34 56 74, which is 0x 12 34 56 78 - 4.

Samir Talwar