In the expression p + a
where p
is a pointer type and a
is an integer, will integer promotion rules apply? For example, if a
is a char
, on a 64-bit machine it will surely be extended to 64 bit before being added to the pointer value (in the compiled assembly), but is it specified by the standards? What will it be promoted to? int
, intptr_t
or ptrdiff_t
? What will unsigned char
or size_t
be converted to?
Pointer arithmetic and integral promotion
1.7k views Asked by Siyuan Ren AtThere are 4 answers
Yes, it is specified in the C++ Standard (paragraph #1 section 5.7 Additive operators) that
the usual arithmetic conversions are performed for operands of arithmetic or enumeration type.
For types (for example char
or unsigned char
) that have rank less than int
the integral promotions will be performed. For size_t
(size_t
has a rank that is not less than the rank of int
or unsigned int
) nothing will be done because there is no a second operand of arithmetic type.
It does not seem required by the standard for any promotion to occur since char
is an integral type:
For addition, either both operands shall have arithmetic or unscoped enumeration type, or one operand shall be a pointer to a completely-defined object type and the other shall have integral or unscoped enumeration type
It seems implementations may depend on the type of pointer additions allowed by the underlying architecture - so if the archtecture supports address+BYTE
- all is good with char
- if not it will likely promote to the smallest address offset size supported.
The result of subtraction of pointers is defined to be of type `std::ptrdiff_t'
When two pointers to elements of the same array object are subtracted, the result is the difference of the subscripts of the two array elements. The type of the result is an implementation-defined signed integral type; this type shall be the same type that is defined as std::ptrdiff_t in the header
C++11 §5.7/1:
“The additive operators
+
and-
group left-to-right. The usual arithmetic conversions are performed for operands of arithmetic or enumeration type.”
This apparently reduces the problem to considering the usual arithmetic conversions, defined by …
C++11 §5/9:
“Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result This pattern is called the usual arithmetic conversions, which are defined as follows:
If either operand is of scoped enumeration type (7.2), no conversions are performed; if the otheroperand does not have the same type, the expression is ill-formed.
If either operand is of type
long double
, the other shall be converted tolong double
.Otherwise, if either operand is
double
, the other shall be converted todouble
.Otherwise, if either operand is
float
, the other shall be converted tofloat
.Otherwise, the integral promotions (4.5) shall be performed on both operands. Then the following rules shall be applied to the promoted operands:
If both operands have the same type, no further conversion is needed.
Otherwise, if both operands have signed integer types or both have unsigned integer types, the operand with the type of lesser integer conversion rank shall be converted to the type of the operand with greater rank.
Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type shall be converted to the type of the operand with unsigned integer type.
Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, the operand with unsigned integer type shall be converted to the type of the operand with signed integer type.
Otherwise, both operands shall be converted to the unsigned integer type corresponding to the type of the operand with signed integer type.”
Followed mechanically, this set of rules would end up in the last bullet point (dash in the standard) and convert a pointer operand to the unsigned integer-type corresponding to something non-existing. Which is just wrong. So the wording “The usual arithmetic conversions are performed for operands of arithmetic or enumeration type” can not be interpreted literally – it's IMHO defective – but must be interpreted like “The usual arithmetic conversions are performed for invocations where both operands are of arithmetic or enumeration type“
So, promotions as such, which are invoked via the usual arithmetic conversions, don't come into play when one operand is a pointer.
But a bit further down in §5.7 one finds …
C++11 §5.7/5:
“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, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integral expression.”
This defines the result entirely in terms of array indexing. For a char
array the difference of subscripts can exceed the range of ptrdiff_t
. A reasonable way for an implementation to arrange this, is to convert the non-pointer argument to the unsigned integral type size_t
(effectively sign extension at the bit level), and use that value with modular arithmetic to compute the resulting pointer value.
I'd say normal integer promotion is applied to
a
. The C-Standard does not provide any specific rules for the conversion of the integer part of an arithmetic operation on a pointer.That is, as
a
is declaredchar
, it is converted to anint
prior to being passed to the+
operator.If one adds a
size_t
it either stays whatsize_t
is defined to be or if (for whatever reasons) it has a smaller rank thenint
it is promoted to anint
.