是"int * ptr = *((& a)+ 1);"凡“一个"标准是否明确定义了int [5]? [英] Is "int *ptr = *( ( &a ) + 1 );" where "a" is int[5] well-defined by the Standard?

查看:139
本文介绍了是"int * ptr = *((& a)+ 1);"凡“一个"标准是否明确定义了int [5]?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基于此问题( c中的奇怪输出问题)关于此行有一个答案(由@Lundin提供):

Based on this Question ( strange output issue in c) there was an Answer ( provided by @Lundin ) about this line:

int *ptr = (int*)(&a+1);

他说的地方:

the cast (int*) was hiding this bug.

所以我提出了以下内容:

So I came with the following:

#include <stdio.h>

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,即:

At some point @chux pointed to §6.3.2.3.7 which is:

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.

但是我不确定我是否理解正确.

But I am not sure if I understand it right.

推荐答案

由于取消引用运算符*:

int *ptr = *( ( &a ) + 1 );

首先,让我们从( &a ) + 1开始.此部分有效. &a的类型为int (*)[5],即指向大小为5的数组的指针.即使a不是数组的元素,通过加1进行指针算术也是有效的.

First, let's start with ( &a ) + 1. This part is valid. &a has type int (*)[5], i.e. a pointer to an array of size 5. Performing pointer arithmetic by adding 1 is valid, even though a is not an element of an array.

C标准的第6.5.6节中详细介绍加法运算符,第7段指出:

In section 6.5.6 of the C standard detailing Additive Operators, paragraph 7 states:

出于这些运算符的目的,指向对象的指针是 不是数组的元素的行为与指向第一个的指针的行为相同 长度为1且对象类型为其数组的元素 元素类型.

For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.

还允许创建一个指针,该指针指向数组末尾的一个元素.因此允许&a + 1.

It's also allowed to create a pointer that points to one element past the end of an array. So &a + 1 is allowed.

问题是当我们取消引用此表达式时.第8段指出:

The problem is when we dereference this expression. Paragraph 8 states:

将具有整数类型的表达式添加或减去时 从指针开始,结果具有指针操作数的类型.如果 指针操作数指向数组对象的元素,并且该数组 足够大,结果指向的元素与 原始元素,使得下标的差异 结果数组元素和原始数组元素等于整数表达式. 换句话说,如果表达式P指向 数组对象,表达式(P)+ N (相当于 N +(P))和(P)-N (其中 N 的值为n)分别指向第i + n个和 数组对象的第i-n个元素(如果存在).而且,如果 表达式 P 指向数组对象的最后一个元素,即 表达式(P)+1 指向数组对象的最后一个元素, 并且如果表达式 q 指向数组的最后一个元素 对象,表达式(Q)-1 指向数组的最后一个元素 目的.如果指针操作数和结果都指向元素 相同的数组对象,或者在数组的最后一个元素之后 目标,评估不得产生溢出;否则, 行为是不确定的. 如果结果指向最后一个元素 数组对象的值,不得用作一元*的操作数 被评估的运算符.

When an expression that has integer 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 integer expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i+n-th and i−n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.

由于不允许将指向数组末尾的指针取消引用,因此行为未定义.

Since dereferencing a pointer to one past the end of an array is not allowed, the beahvior is undefined.

返回引用的帖子中的表达式:

Going back to the expression in the referenced post:

int *ptr = (int*)(&a+1);
printf("%d %d", *(a+1), *(ptr-1));

这也是未定义的行为,但原因有所不同.在这种情况下,将int (*)[5]转换为int *,然后使用转换后的值.使用此类转换后的值合法的唯一情况是将对象指针转换为字符类型的指针时,例如: char *unsigned char *,随后取消引用以读取对象表示形式的字节.

This is also undefined behavior but for a different reason. In this case, a int (*)[5] is converted to int * and the converted value is subsequently used. The only case where using such a converted value is legal is when converting an object pointer to a pointer to a character type, e.g. char * or unsigned char * and subsequently dereferenced to read the bytes of the object's representation.

似乎上面的两行实际上定义清楚.在发生指针取消引用*(ptr-1)时,所访问的对象的有效类型为int,该类型与ptr-1的取消引用类型匹配.将指针值&a+1int (*)[5]强制转换为int *是有效的,并且对强制转换的指针值执行指针算术也是有效的,因为它指向a的内部或指向其后的一个元素.

It seems the two lines above are actually well defined. At the time the pointer dereference *(ptr-1) occurs, the object being accessed has effective type int, which matches the dereferenced type of ptr-1. Casting the pointer value &a+1 from int (*)[5] to int * is valid, and performing pointer arithmetic on the casted pointer value is also valid because it points either inside of a or one element past it.

这篇关于是"int * ptr = *((&amp; a)+ 1);"凡“一个"标准是否明确定义了int [5]?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆