Difference in results when using int and size_t

I read an article about using the data types size_t and ptrdiff_t here when I came across this example:

enter image description here

Code:

 int A = -2; unsigned B = 1; int array[5] = { 1, 2, 3, 4, 5 }; int *ptr = array + 3; ptr = ptr + (A + B); //Error printf("%i\n", *ptr); 

I canโ€™t understand a couple of things. First, how do I add the number signed and unsigned , type the result of the input into an unsigned type? If the result is really 0xFFFFFFFF type unsigned , why, in a 32-bit system, adding it with ptr will interpret it as ptr-1 , considering that the number is really unsigned and 1 should not mean a sign?

Secondly, why is the result different from a 64-bit system?

Can someone explain this please?

+6
source share
3 answers

1. I canโ€™t understand a couple of things. First, how to add a signed and unsigned number, enter the input result in an unsigned type?

This is determined by integer shares and an integer rank conversion.

6.3.1.8 p1: Otherwise, if an operand with an unsigned integer type has a rank greater than or equal to the ranks of the type of another operand, then the operand with an integer type with a sign is converted to the type of the unsigned operand of an integer type.

In this case, unsigned has a higher rank than int, so int is assigned unsigned.

Converting int (-2) to unsigned is done as described:

6.3.1.3 p2: Otherwise, if the new type is unsigned, the value is converted by repeatedly adding or subtracting one greater than the maximum value that can be represented in the new type until the value is in the range of the new type

2. If the result is really 0xFFFFFFFF of unsigned type, why in a 32-bit system, adding it with ptr, will it be interpreted as ptr-1, given that the number is actually unsigned, and the leading 1 should not mean a sign?

This behavior is undefined and cannot be relied on, since C does not define pointer arithmetic overflows.

6.5.6 p8: If both the operand and the result pointers point to the elements of the same array object or one after the last element of the array object, the evaluation should not lead to overflow; otherwise, the behavior is undefined.

3. Secondly, why is the result different from a 64-bit system?

(This assumes (like the image) that int and unsigned have 4 bytes.)

The result of A and B is the same as described in 1., then this result is added to the pointer. Since the pointer has 8 bytes and it is assumed that the addition does not overflow (anyway, if ptr had a large address, giving the same undefined behavior as in 2.), the result is the address.

This behavior is undefined because the pointer points outside the bounds of the array.

+4
source

The operands of the expression A + B obey the usual arithmetic conversion covered in C11 (n1570) 6.3.1.8 p1:

[...]

Otherwise, entire stocks [which leave int and unsigned int unchanged] are executed on both operands. Then, the following rules apply to advanced operands:

  • If both operands are of the same type, [...]
  • Otherwise, if both operands are integer types or both have unsigned integer types, [...]
  • Otherwise, if the operand having an unsigned integer type has a rank greater than or equal to the ranks of the type of another operand, then the operand with an integer type sign is converted to the operand type with an unsigned integer.
  • [...]

The int and unsigned int types have the same rank (ibid., 6.3.1.1 p1, 4 th bullet); the result of the addition is of type unsigned int .

On 32-bit systems, int and pointers are usually the same size (32 bits). From a hardware-oriented point of view (and assuming 2 additions), subtracting 1 and adding -1u same (adding for signed and unsigned types is the same!), So access to the array element seems to work.

However, this behavior is undefined, since array does not contain the element 0x100000003 rd .

In 64-bit mode, an int usually has 32 bits, but pointers have 64 bits. Thus, there is no deception and no equivalence for subtracting 1 (from a hardware-oriented point of view, the behavior is undefined in both cases).

To illustrate, say ptr - 0xabcd0123, adding 0xffffffff gives

  abcd0123 + ffffffff 1abcd0122 ^-- The 1 is truncated for a 32-bit calculation, but not for 64-bit. 
+2
source

In most 64 bits, int is 32 bits, but on 32-bit systems, pointers are also 32 bits.

Recall that in 32-bit arithmetic - on two-component based equipment , adding 0xFFFFFFFF almost the same as subtracting 1: it overflows and you get the same number minus 1 (this is the same phenomenon when you add 9 to a number from 0 to 9, you get than the number minus 1 and carry). On this type of hardware, encoding -1 is actually the same value 0xFFFFFFFF , only the operation is different (the signature is added against unsigned add), and therefore the transfer will be carried out in an unsigned case.

In 64-bit pointers ... 64 bits. Adding a 32-bit value to the 64-bit version requires expanding this 32-bit value to 64. The unsigned values โ€‹โ€‹are zero (that is, the missing bits are filled with zeros), while the signed values โ€‹โ€‹are expanded with characters (that is, with the value of the signed sign).

In this case, adding an unsigned value (which, therefore, will not be expanded with a sign) will not overflow, which will lead to a completely different value from the original.

+1
source

Source: https://habr.com/ru/post/978244/


All Articles