简体   繁体   English

指针算术和积分提升

[英]Pointer arithmetic and integral promotion

In the expression p + a where p is a pointer type and a is an integer, will integer promotion rules apply? 在表达式p + a ,其中p是指针类型,而a是整数,是否适用整数提升规则? 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? 例如,如果achar ,则在64位计算机上,在将其添加到指针值(在已编译程序集中)之前,它一定会扩展为64位,但是它是由标准指定的吗? What will it be promoted to? 它会被推广到什么? int , intptr_t or ptrdiff_t ? intintptr_t还是ptrdiff_t What will unsigned char or size_t be converted to? unsigned charsize_t将转换为什么?

It does not seem required by the standard for any promotion to occur since char is an integral type: 由于char是一个整数类型,因此似乎不需要进行任何晋级就可以了:

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. 看来实现可能取决于基础体系结构所允许的指针添加类型-因此,如果架构支持address+BYTE一切都很好用char否则,它可能会提升为所支持的最小地址偏移量。

The result of subtraction of pointers is defined to be of type `std::ptrdiff_t' 指针相减的结果定义为“ 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 此类型应与标头中定义为std :: ptrdiff_t的类型相同

C++11 §5.7/1: 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: 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; 如果两个操作数都属于范围枚举类型(7.2),则不执行任何转换。 if the otheroperand does not have the same type, the expression is ill-formed. 如果otheroperand不具有相同的类型,则表达式格式错误。

  • If either operand is of type long double , the other shall be converted to long double . 如果一个操作数的类型为long double ,则另一个应转换为long double

  • Otherwise, if either operand is double , the other shall be converted to double . 否则,如果其中一个操作数为double ,则另一个应转换为double

  • Otherwise, if either operand is float , the other shall be converted to float . 否则,如果其中一个操作数为float ,则另一个应转换为float

  • Otherwise, the integral promotions (4.5) shall be performed on both operands. 否则,应在两个操作数上执行积分提升(4.5)。 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 … 但是在第5.7节中,人们发现……

C++11 §5.7/5: 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 . 对于char数组,下标的差可以超过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. 一个实现的合理安排是将非指针参数转换为无符号整数类型size_t (在位级别有效地进行符号扩展),然后将该值与模块化算法一起使用以计算结果指针值。

I'd say normal integer promotion is applied to a . 我想说的正常整数推广应用到a The C-Standard does not provide any specific rules for the conversion of the integer part of an arithmetic operation on a pointer. C标准没有为指针上的算术运算的整数部分的转换提供任何特定的规则。

That is, as a is declared char , it is converted to an int prior to being passed to the + operator. 也就是说,由于将a声明为char ,因此在将其传递给+运算符之前将其转换为int

If one adds a size_t it either stays what size_t is defined to be or if (for whatever reasons) it has a smaller rank then int it is promoted to an int . 如果再加一个size_t ,要么什么住宿size_t被定义为,或者如果(无论何种原因)它具有较小的排名则int它提升到int

Yes, it is specified in the C++ Standard (paragraph #1 section 5.7 Additive operators) that that 是的,在C ++标准(第1节第5.7节“加法运算符”)中规定,

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 promotion will be performed. 对于等级小于int的类型(例如char或unsigned char),将执行积分提升。 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. 对于size_t(size_t的秩不小于int或unsigned int的秩),将不会执行任何操作,因为没有算术类型的第二个操作数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM