English 中文(简体)
限制的正式定义没有说明有效案件
原标题:Formal definition of restrict fails to account for valid cases

The following reasonable program seems to have undefined behavior according to the formal definition of restirct in the C standard:

void positive_intcpy(int * restrict q, const int * restrict p, size_t n) {
  int *qBgn = q;
  const int *pEnd = p + n;
  // sequence point S
  while (p != pEnd && *p>0) *q++ = *p++;
  if (q != qBgn) fprintf(stderr,"Debug: %d.
",*(q-1)); // undefined behavior!?
}
int main(void) {
  int a[6] = {4,3,2,1,0,-1};
  int b[3];
  positive_intcpy(b,a,3);
  return 0;
}

The function copies integers from one array to another, as long as the integers are positive. The fprintf call displays the last positive integer that was copied (if any). There is never any aliasing between p and q.

这是否真的是“联邦”?

这个问题涉及99标准第6.7.3.1节。 相关案文在

我们正在讨论上面标注的“q-1”。 是否以<条码>p<>/条码>指定限点物体为准?

The standard says:

如下文所示:标语<编码>E>>。 [P is a limit-standard pointer Object] if (at some series point in the implementation of B [,B>>在/code>评价之前宣布的栏目]修改<代码>P,指明其原先指明的阵列物体的拷贝将更改<代码>的价值。 E [见脚注]。 请注意,“基于”的定义仅限于指点型的表述。

[脚注] 换言之,<代码>E取决于<代码>的价值。 P 本身,而不是通过<代码>间接参照的物体的价值。 P 。 例如,如果识别符号p(int **restrict),则点代码p+1基于指定的限点物体(<>p),但点符号<*p和p>>>>>>>>>>>>>>>>>>>>

在我们的节目中,在上面标注的<代码>S上,修改<代码>p,以注明<代码>a阵列的复印件,将造成<代码>p != pEnd永远有效(because p>。 最终未与<代码>p一起修改,因此,该细则将持续到<代码>*p>0成为不实之词,因此,在整条末尾的<代码>q的价值将发生变化(这将是一个机器字)。 因此,我们的结论是,我们的表述是<代码>q-1。

Now the standard says:

During each execution of B, let L be any lvalue that has &L based on P. If L is used to access the value of the object X that it designates, and X is also modified (by any means), then the following requirements apply: T [where T is the type to which P is declared to point] shall not be const-qualified. Every other lvalue used to access the value of X shall also have its address based on P. Every access that modifies X shall be considered also to modify P, for the purposes of this subclause. If P is assigned the value of a pointer expression E that is based on another restricted pointer object P2, associated with block B2, then either the execution of B2 shall begin before the execution of B, or the execution of B2 shall end prior to the assignment. If these requirements are not met, then the behavior is undefined.

就我们的情况而言,<代码>L>*(q-1).X&>的物体;b>在<编码>B上作了修改,其数值为2<<>>>>。 但是,Tconst int,这意味着该方案有UB。

You might say that this is harmless, because the compiler will probably not take advantage of such a hard to prove UB case and so won t mis-optimize it.

但同样的逻辑可以反向地适用,而这种逻辑确实是危险的:

int f(int *restrict p, int *restrict q) {
  int *p0=p, *q0=q;
  // sequence point S
  if (p != p0) q++;
  if (q != q0) p++;
  *p = 1;
  *q = 2;
  return *p + *q;
}
int main(void) {
  int x;
  printf("%d
", f(&x,&x));
  return 0;
}

GCC does optimize here. GCC -O0 prints 4, while GCC -O3 prints 3. Unfortunately, reading the standard literally, GCC must be wrong.

因此:

  1. In the expression *q = 2, q is "based on" p (because if p was modified at sequence point S to point to a copy of x, the conditional p != p0 would become true, changing the value of q).
  2. In the expression *p = 1, p is "based on" q (because if q was modified at sequence point S to point to a copy of x, the conditional q != q0 would become true, changing the value of p).
  3. In the body of f, any access to any object via a pointer expression is always both "based on" p and "based on" q. So no restrict-violation, neither of restrict p, nor of restrict q. Note that no restrict-qualified pointer is ever assigned a pointer expression inside f (because p++ and q++ do not actually happen).
  4. Since there is no restrict violation, the program doesn t have UB and the compiler is not allowed to optimize.

在我看来,该标准未能按预期方式界定“基于”的定义。 那么,打算采取何种方式? 我指的是,显然有意图的含义,使海合会得以优化,我认为海合会在此案中在道义上是正确的。 我想避免撰写可能不理想的方案。

问题回答

我认为,6.7.3.1p3的措辞允许你提到的情况,同时违背了预期的含义。

第6.7.3p8节首先提到意图:

An object that is accessed through a restrict-qualified pointer has a special association with that pointer. This association, defined in 6.7.3.1 below, requires that all accesses to that object use, directly or indirectly, the value of that particular pointer.

因此,通过这一说明,q q-1以标的q为基础,而不是标的<代码>p

第6.7.3.1p7节举例说明:

EXAMPLE 1 档案范围申报

int * restrict a;
int * restrict b;
extern int c[];

assert that if an object is accessed using one of a, b, or c, and that object is modified anywhere in the program, then it is never accessed using either of the other two

这进一步证实了这一意图。

严格阅读6.7.3.1p3时,<代码>q-1<>/code>的表述依据是:<代码>p和q,两者似乎都有意义,与上述描述和实例背道而驰。

我认为,6.7.3.1p3的意图是抓住过境表达,例如:

int x[5];
int * restrict p = x;
int *p1 = p+2;    // p1 is based on p
int *p2 = p1-1;   // p2 is also based on p

简单地说,“包括<代码>p在内的表述在其操作中”就这样一例。

www.un.org/Depts/DGACM/index_french.htm

如下文之一的点言:

  • E contains P as an operand
  • E contains an lvalue V as an operand, and V was set to the value of an expression E2 which is based on P.

Is this really UB, or is my reasoning wrong?

你的推理不符合具体意图。

在我们的节目中,在上面标注的<代码>S上,修改<代码>p,以注明<代码>a阵列的复印件,将造成<代码>p != pEnd永远有效(because p>。 最终不与<代码>p一起修改

但是,从中得出这种看法和推理并不是要说什么。 它不关心控制流动的变化所产生的差异,如你所代表的变化。 确实很难准确描述,因此,或许你可以宽恕委员会,但这里要说:

  • 考虑执行该方案,并研究所有对表达评价的副作用,这些评价影响对表达方式的某些评价的价值。 E 。

  • 设想对所描述的<代码>p的价值进行更改,并再进行所有相同的评价,同时考虑到<代码>p的变更值和通过结果传播的差别,但不选择更多的、更少的或不同的表述来评价,也不按不同的顺序进行。

  • 最终评价<代码> E 产生不同价值,<代码> E基于p

这不是完美的,我想不要说,但我希望,解释一下我们所说的话与你现在所说的话之间的区别是充分的。

有鉴于此,我希望你看到,在某些经过仔细挑选的地方,对<代码>p<>>/代码”价值的改变可能会造成不同程度的评价。 在评价“基于”时,我们审视了评价对were<>/em>的影响,而不是可能改变评价顺序。

由于q q - 1实际上不是“基于”<代码>p的,从光谱的意义上讲,该方案并不违反与<编码>restrict-有资质的类型有关的要求。


但是,在相反的情况下也可以适用同样的逻辑。

......无关紧要,因为它首先是错误的。

但请举一例研究该方案:

int f(int *restrict p, int *restrict q) {
  int *p0=p, *q0=q;
  // sequence point S
  if (p != p0) q++;
  if (q != q0) p++;
  *p = 1;
  *q = 2;
  return *p + *q;
}
int main(void) {
  int x;
  printf("%d
", f(&x,&x));
  return 0;
}

<代码>p,p0,p != p0p++/code>均以p为基础,但并非以q 为准。

<代码>q,q0,q !=q0,和q++均以q为基础,但并非以<编码>p为准。

Either *p*q 可填充光谱代码的作用,而另一条标本的条目是restrict-violating change to the one underlying Object. 因此,这种行为没有定义,海合会可以做它想要的一切。





相关问题
Fastest method for running a binary search on a file in C?

For example, let s say I want to find a particular word or number in a file. The contents are in sorted order (obviously). Since I want to run a binary search on the file, it seems like a real waste ...

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

Tips for debugging a made-for-linux application on windows?

I m trying to find the source of a bug I have found in an open-source application. I have managed to get a build up and running on my Windows machine, but I m having trouble finding the spot in the ...

Trying to split by two delimiters and it doesn t work - C

I wrote below code to readin line by line from stdin ex. city=Boston;city=New York;city=Chicago and then split each line by ; delimiter and print each record. Then in yet another loop I try to ...

Good, free, easy-to-use C graphics libraries? [closed]

I was wondering if there were any good free graphics libraries for C that are easy to use? It s for plotting 2d and 3d graphs and then saving to a file. It s on a Linux system and there s no gnuplot ...

Encoding, decoding an integer to a char array

Please note that this is not homework and i did search before starting this new thread. I got Store an int in a char array? I was looking for an answer but didn t get any satisfactory answer in the ...