指针算术和积分提升



在表达式p + a中,p是指针类型,a是整数,整数升级规则是否适用?例如,如果a是一个char,在 64 位机器上,它肯定会扩展到 64 位,然后再添加到指针值(在编译的程序集中),但它是由标准指定的吗?它将被提升到什么? intintptr_t还是ptrdiff_tunsigned charsize_t将转换为什么?

标准似乎不需要进行任何升级,因为char是一个整体类型:

对于加法,两个操作数都应具有算术或无作用域枚举类型,或者一个操作数应是指向完全定义的对象类型的指针,另一个操作数应具有整体或无作用域枚举类型

似乎实现可能取决于底层架构允许的指针添加类型 - 所以如果架构支持address+BYTE - 一切都很好char - 如果不是,它可能会提升到支持的最小地址偏移大小。

指针减去的结果定义为类型为"std::p trdiff_t"

当减去指向同一数组对象的元素的两个指针时,结果是两个数组元素的下标之差。结果的类型是实现定义的有符号整数类型;此类型应与标头中定义为 std::p trdiff_t 的类型相同

C++11 §5.7/1:

"添加剂操作员从左到右+-分组。通常的算术转换是对算术或枚举类型的操作数执行的。

这显然将问题简化为考虑通常的算术转换,由...

C++11 §5/9:

"许多期望算术操作数或 枚举类型导致转换和产生结果类型类似 道路。目的是产生一个通用类型,这也是 结果 这种模式称为通常的算术转换, 定义如下:

  • 如果任一操作数为作用域枚举类型 (7.2),则不执行转换;如果另一个操作数的类型不同,则表达式格式不正确。

  • 如果其中一个操作数是类型 long double,另一个应转换为 long double

  • 否则,如果其中一个操作数double,另一个操作数应转换为 double

  • 否则,如果其中一个操作数float,另一个应转换为 float

  • 否则,应在两个操作数上执行积分提升 (4.5)。然后,以下规则应应用于提升的操作数:

    • 如果两个操作数的类型相同,则无需进一步转换。

    • 否则,如果两个操作数都具有有符号整数类型
    • 或都具有无符号整数类型,则整数转换秩较小的操作数应转换为具有较大秩的操作数的类型。

    • 否则,如果具有无符号整数类型的操作数
    • 的秩大于或等于其他操作数类型的秩,则具有有符号整数类型的操作数应转换为具有无符号整数类型的操作数的类型。

    • 否则,如果带符号整数类型的操作数的类型可以表示无符号整数类型的操作数类型的
    • 所有值,则无符号整数类型的操作数应转换为带符号整数类型的操作数的类型。

    • 否则,两个操作数都应转换为与具有有符号整数类型的操作数类型相对应的无符号整数类型。

按照机械的方式,这组规则将出现在最后一个项目符号点(标准中的破折号)中,并将指针操作数转换为对应于不存在的内容的无符号整数类型。这是错误的。因此,"通常的算术转换是为算术或枚举类型的操作数执行的"的措辞不能从字面上解释——恕我直言,这是有缺陷的——但必须解释为"通常的算术转换是为两个操作数都是算术或枚举类型的调用执行的"

因此,当一个操作数是一个指针时,通过通常的算术转换调用的此类提升不会发挥作用。

但是在§5.7的更下方,人们发现...

C++11 §5.7/5:

"当在指针中添加或减去具有整型类型的表达式时,结果具有指针操作数的类型。如果指针操作数指向数组对象的某个元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得生成的数组元素和原始数组元素的下标之差等于整数表达式。

这完全根据数组索引来定义结果。对于char数组,下标的差异可以超过 ptrdiff_t 的范围。实现安排这一点的一种合理方法是将非指针参数转换为无符号整数类型 size_t(在位级别有效地进行符号扩展),并将该值与模块化算术一起使用来计算生成的指针值。

我会说正常的整数提升适用于a。C 标准没有为指针上算术运算的整数部分的转换提供任何特定规则。

也就是说,当a被声明为char时,它在传递给+运算符之前被转换为int

如果添加一个size_t它要么保持size_t被定义为的样子,要么如果(无论出于何种原因)它的排名较小,那么int它被提升为int

是的

,在C++标准(段落 #1 第 5.7 节加法运算符)中指定

通常的算术转换是针对算术或枚举类型。

对于排名低于int的类型(例如charunsigned char),将执行积分提升。对于size_tsize_t的秩不低于intunsigned int的秩),什么都不会做,因为没有第二个算术类型的操作数。

最新更新