简体   繁体   English

在指定指针时使用指向内容

[英]Using pointed to content in assignment of a pointer

It has always been my understanding that the lack of a sequence point after the reading of the right expression in an assignment makes an example like the following produce undefined behavior: 我一直认为,在赋值中读取正确表达式后缺少序列点会产生如下示例,产生未定义的行为:

void f(void)
{
   int *p;
   /*...*/
   p = (int [2]){*p};
   /*...*/
}
// p is assigned the address of the first element of an array of two ints, the
// first having the value previously pointed to by p and the second, zero. The
// expressions in this compound literal need not be constant. The unnamed object
// has automatic storage duration.

However, this is EXAMPLE 2 under "6.5.2.5 Compound literals" in the committee draft for the C11 standard, the version identified as n1570, which I understand to be the final draft (I don't have access to the final version). 但是,这是C11标准委员会草案中“6.5.2.5复合文字”下的例2,该版本标识为n1570,我理解为最终草案(我无法访问最终版本)。

So, my question: Is there something in the standard that gives this defined and specified behavior? 所以,我的问题是:标准中是否有某些内容可以提供此定义和指定的行为?

EDIT 编辑

I would like to expound on exactly what I see as the problem, in response to some of the discussion that has come up. 我想详细阐述我所看到的问题,以回应一些已经提出的讨论。

We have two conditions under which an assignment is explicitly stated to have undefined behavior, as per 6.5p2 of the standard quoted in the answer given by dbush: 根据dbush给出的答案中引用的6.5p2标准,我们有两个条件明确指出赋值具有未定义的行为:

1) A side effect on a scalar object is unsequenced relative to a different side effect on the same scalar object. 1)相对于对同一标量对象的不同副作用,对标量对象的副作用是无效的。

2) A side effect on a scalar object is unsequenced relative to a value computation using the value of the same scalar object. 2)相对于使用相同标量对象的值的值计算,对标量对象的副作用是未序的。

An example of item 1 is "i = ++i + 1". 项目1的示例是“i = ++ i + 1”。 In this case the side effect of writing the value i+1 into i due to ++i is unsequenced relative to the side effect of assigning the RHS to the LHS. 在这种情况下,由于++ i而将值i + 1写入i的副作用相对于将RHS分配给LHS的副作用而言是无效的。 There is a sequence point between the value calculations of each side and the assignment of RHS to LHS, as described in 6.5.16.1 given in the answer by Jens Gustedt below. 每一侧的值计算和RHS与LHS的分配之间存在一个序列点,如下面Jens Gustedt的答案中给出的6.5.16.1中所述。 However, the modification of i due to ++i is not subject to that sequence point, otherwise the behavior would be defined. 但是,由于++ i对i的修改不受该序列点的限制,否则将定义行为。

In the example I give above, we have a similar situation. 在上面给出的例子中,我们有类似的情况。 There is a value computation, which involves the creation of an array and the conversion of that array to a pointer to its first element. 有一个值计算,它涉及创建一个数组并将该数组转换为指向其第一个元素的指针。 There is also a side effect of writing a value to part of that array, *p to the first element. 将值写入该数组的一部分,* p到第一个元素也有副作用。

So, I don't see what gaurantees we have in the standard that the modification of the otherwise uninitialized first element of the array will be sequenced before the writing of the array address to p. 所以,我没有看到我们在标准中有什么样的gaurantees,在将数组地址写入p之前,对数组的其他未初始化的第一个元素的修改将被排序。 What about this modification (writing *p to the first element) is different from the modification of writing i+1 to i? 这个修改(将* p写入第一个元素)与将i + 1写入i的修改有何不同?

To put it another way, suppose an implementation looked at the statement of interest in the example as three tasks: 1st, allocate space for the compound literal object; 换句话说,假设一个实现将示例中的兴趣语句看作三个任务:第一,为复合文字对象分配空间; 2nd: assign a pointer to said space to p; 第二步:将指向所述空间的指针分配给p; 3rd: write *p to the first element in the newly allocated space. 3rd:将* p写入新分配空间中的第一个元素。 The value computation for both RHS and LHS would be sequenced before the assignment, as computing the value of the RHS only requires the address. 在分配之前,RHS和LHS的值计算将被排序,因为计算RHS的值仅需要地址。 In what way is this hypothetical implementation not standard compliant? 这个假设的实现以何种方式不符合标准?

You need to look at the definition of the assignment operator in 6.5.16.1 您需要查看6.5.16.1中赋值运算符的定义

The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands. 在左右操作数的值计算之后,对更新左操作数的存储值的副作用进行排序。 The evaluations of the operands are unsequenced. 对操作数的评估是不确定的。

So here you clearly see that first it evaluates the expressions on both sides in any order or even concurrently, and then stores the value of the right into the object designated by the left. 所以在这里你清楚地看到,它首先以任何顺序或甚至同时评估两侧的表达式, 然后将右边的值存储到左边指定的对象中。

Additionally, you should know that LHS and RHS of an assignment are evaluated differently. 此外,您应该知道分配的LHS和RHS的评估方式不同。 Citations are a bit too long, so here is a summary 引文有点太长了,所以这里有一个总结

  • For the LHS the evaluation leaves "lvalues", that is objects such as p , untouched. 对于LHS,评估留下“左值”,即p等对象未触及。 In particular it doesn't look at the contents of the object. 特别是它不会查看对象的内容。

  • For the RHS there is "lvalue conversion", that is for any object that is found there (eg *p ) the contents of that object is loaded. 对于RHS,存在“左值转换”,即对于在那里找到的任何对象(例如, *p ),加载该对象的内容

  • If the RHS contains an lvalue of array type, this array is converted to a pointer to its first element. 如果RHS包含数值类型的左值,则此数组将转换为指向其第一个元素的指针。 This is what is happening to your compound literal. 这就是你的复合文字所发生的事情。

Edit: You added another question 编辑:您添加了另一个问题

What about this modification (writing *p to the first element) is different from the modification of writing i+1 to i? 这个修改(将* p写入第一个元素)与将i + 1写入i的修改有何不同?

The difference is simply that i in the LHS of the assignment and thus has to be updated. 不同之处仅在于i在分配的LHS中,因此必须进行更新。 The array from the compound literal is not in the LHS and thus is of no concern for the update. 复合文字中的数组不在LHS中,因此不关心更新。

Section 6.5p2 of the C standard details why this is valid: C标准的第6.5p2节详细说明了这一点的有效性:

If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. 如果相对于对同一标量对象的不同副作用或使用相同标量对象的值进行值计算,对标量对象的副作用未被排序,则行为未定义。 If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings. 如果表达式的子表达式有多个允许的排序,则如果在任何排序中发生这种未测序的副作用,则行为是不确定的。 84) 84)

And footnote 84 states: 脚注84指出:

84) This paragraph renders undefined statement expressions such as 84)此段落呈现未定义的语句表达式,如

 i = ++i + 1; a[i++] = i; 

while allowing 允许的同时

 i = i + 1; a[i] = i; 

The posted snippet from 6.5.2.5 falls under the latter, as there is no side effect. 来自6.5.2.5的已发布片段属于后者,因为没有副作用。

In (int [2]){*p} , *p provides an initial value for the compound literal. (int [2]){*p}*p提供复合文字的初始值。 This is not an assignment, and it is not a side effect. 这不是一项任务,也不是副作用。 The initial value is part of the object when the object is created. 创建对象时,初始值是对象的一部分。 There is no moment when the array exists and it is not initialized. 没有数组存在且没有初始化的时刻。

In p = (int [2]){*p} , we know the side effect of updating p is sequenced after the computation of the right side because C 2011 [N1570] 6.5.16 3 says “The side effect of updating the stored value of the left operand is sequenced after the value computations of the left and right operands.” p = (int [2]){*p} ,我们知道在计算右侧之后更新p的副作用是有序的,因为C 2011 [N1570] 6.5.16 3说“更新存储的副作用在左右操作数的值计算之后,左操作数的值被排序。“

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

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