我可以减去或比较受限制的指针吗?

Can I subtract or compare restricted pointers?

问题:

如果我有两个指针(本质上是一个begin和一个end)用restrict限定。 begin 指针用于 dereferencing/reading,而 end 指针是一个永远不会取消引用的尾数指针,仅用于检查范围的大小(通过 end - begin)。一旦范围被消耗,我希望 beginend 相等并且 end - begin 为 0,尽管此时这两个指针永远不会被取消引用。

鉴于 restrict 对指针的限制,减去和比较这两个指针是否是明确定义的行为?

MVCE:

我有一些代码如下:

#include <stddef.h>

struct Reader {
  const char* restrict data;
  size_t size;
};

char read_char(struct Reader* reader) {
  --reader->size;
  return *reader->data++;
}

int main(int argc, char* argv[]) {
  struct Reader reader = {
    .data = argv[1],
    .size = argv[1] ? strlen(argv[1]) : 0,
  };

  if (reader.size > 0) {
    return read_char(&reader);
  }
  return 0;
}

我想修改一下,这样阅读时就不用同时修改datasize,只需要修改data:

#include <stddef.h>

struct Reader {
  const char* restrict data;
  const char* restrict end;  // Not sure if this should be restrict or not.
};

char read_char(struct Reader* reader) {
  return *reader->data++;
}

int main(int argc, char* argv[]) {
  struct Reader reader = {
    .data = argv[1],
    .end = argv[1] + (argv[1] ? strlen(argv[1]) : 0),
  };

  if (reader.end - reader.data > 0) {  // Is this okay?
    return read_char(&reader);
  }
  return 0;
}

考虑到 restrict 对指针的限制,这是允许的吗?

TL;DR:根据我对标准的阅读,您的使用是允许的。

标准对使用 restrict 限定指针的要求都与别名和对指向对象的访问有关。我发现使用这样的指针作为指针差分运算符(-)的操作数没有任何限制,并且这样的限制不符合restrict的目的(这是为了提供更大的优化机会)。

相比之下,通过添加整数从 restrict 限定的指针获得的指针值是 "based on" 在某种意义上对标准很重要的原始指针。粗略地说,通过这样的指针访问指向的对象是可以接受的,而通过指向不是 "based on" 受限指针的同一对象的指针访问该对象是不可接受的。

此外,我认为 Reader.end 不需要 restrict 资格,而且我认为这样的资格对您根本没有帮助。但是,您必须确保 Reader.end 或派生自它的任何指针均未用于访问数据;为此,您只能使用 Reader.data。在 main() 中也是如此。 另一方面,如果您无处修改指向的对象,几乎所有这些都没有实际意义。

标准或基本原理中没有任何内容表明有任何意图禁止对 restrict 限定指针进行比较或计算。然而,标准定义一个指针是 "based upon" 另一个指针的概念的方式与比较奇怪地相互作用。例如,给定如下内容:

int test(int *restrict p, int *q, int i)
{
  p[i] = 1;
  if (p+1 == q)
    p[1] = 2;
  return p[i];
}

用指向已识别数组副本的指针替换 p 会阻止对 p[1] 的赋值,从而无法回答此类替换是否会影响该赋值中使用的地址的问题。虽然 p[1] 基于 p 看起来很明显,而且比较会影响它似乎很荒谬,但 clang 和 gcc 都不认为上面的左值 p[1] 是基于与左值 p[i].

相同 p