基于这个问题( c中的奇怪输出问题 )有一个答案( 由@Lundin提供 )关于这一行:
int *ptr = (int*)(&a+1);
在哪里他说:
the cast (int*) was hiding this bug
。
所以我带来了以下内容:
#include int main( void ){ int a[5] = {1,2,3,4,5}; int *ptr = *( ( &a ) + 1 ); printf("%d", *(ptr-1) ); }
我想知道这是否:
int *ptr = *( ( &a ) + 1 );
标准明确定义了吗?
编辑 :
在某些时候,@ chux指向§6.3.2.3.7
,它是:
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned68) for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer. When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.
但我不确定我是否理解正确。
此表达式作为解除引用运算符*
的结果调用未定义的行为:
int *ptr = *( ( &a ) + 1 );
首先,让我们从( &a ) + 1
。 这部分是有效的。 &a
具有类型int (*)[5]
,即指向大小为5的数组的指针。即使a
不是数组的元素,通过添加1来执行指针运算也是有效的。
在C标准详细说明添加剂操作员的第6.5.6节中,第7段规定:
出于这些运算符的目的,指向不是数组元素的对象的指针与指向长度为1的数组的第一个元素的指针的行为相同,其中对象的类型为其元素类型。
它还允许创建一个指针指向一个元素超过数组末尾的指针。 所以&a + 1
是允许的。
问题是当我们取消引用这个表达式时。 第8段规定:
当一个具有整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。 如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果元素和原始数组元素的下标的差异等于整数表达式。 换句话说,如果表达式P指向数组对象的第i个元素,则表达式(P)+ N (等效地, N +(P) )和(P)-N (其中N具有值n)指向分别为数组对象的第i + n和第i-n个元素,只要它们存在。 此外,如果表达式P指向数组对象的最后一个元素,则表达式(P)+1指向数组对象的最后一个元素之后的一个,如果表达式q指向一个超过数组对象的最后一个元素,表达式(Q)-1指向数组对象的最后一个元素。 如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不应产生溢出; 否则,行为未定义。 如果结果指向数组对象的最后一个元素之后,则不应将其用作已计算的一元
*
运算符的操作数。
由于不允许取消引用指向一个超过数组末尾的指针,因此未定义beahvior。
回到引用post中的表达式:
int *ptr = (int*)(&a+1); printf("%d %d", *(a+1), *(ptr-1));
这也是未定义的行为,但原因不同。 在这种情况下, int (*)[5]
被转换为int *
,随后使用转换后的值。 使用这种转换值的唯一情况是合法的是将对象指针转换为指向字符类型的指针,例如char *
或unsigned char *
,然后取消引用以读取对象表示的字节。
编辑:
看来上面的两行实际上已经很明确了。 在指针解除引用*(ptr-1)
发生时,被访问的对象具有有效类型int
,其匹配解除引用的类型ptr-1
。 将指针值&a+1
从int (*)[5]
为int *
是有效的,并且对转换指针值执行指针算法也是有效的,因为它指向a
或一个元素之后。
*( ( &a ) + 1 )
是因为UB
…如果结果指向数组对象的最后一个元素之后,则不应将其用作评估的一元
*
运算符的操作数。 C11§6.5.68
( &a ) + 1
分指向“一个过去”。 使用*
就是“不会”。
int a[5] = {1,2,3,4,5}; int *ptr = *( ( &a ) + 1 );
即使a
是int a
因此适用
出于这些运算符的目的,指向不是数组元素的对象的指针与指向长度为1的数组的第一个元素的指针的行为相同,其中对象的类型为其元素类型。 §6.5.67
int *ptr = *( ( &a ) + 1 );
调用未定义的行为。
C11 – §6.5.6“添加剂操作员”(P8):
当一个具有整数类型的表达式被添加到指针或从指针中减去时,结果具有指针操作数的类型。 如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,使得结果元素和原始数组元素的下标的差异等于整数表达式。 换句话说,如果表达式
P
指向数组对象的第i
个元素,则表达式(P)+N
(等效地,N+(P)
)和(P)-N
(其中N
具有值n
)指向分别为数组对象的第i+n
和第i−n
个元素,只要它们存在即可。 此外,如果表达式P
指向数组对象的最后一个元素,则表达式(P)+1
指向一个超过数组对象的最后一个元素,如果表达式Q
指向一个超过数组对象的最后一个元素,表达式(Q)-1
指向数组对象的最后一个元素。[…]
以上就是c/c++开发分享是“int * ptr = *((&a)+ 1);”其中“a”是由标准明确定义的int ?相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/553078.html