【问题标题】:Can I subtract or compare restricted pointers?我可以减去或比较受限指针吗?
【发布时间】:2016-08-02 15:24:04
【问题描述】:

问题:

如果我有两个用restrict 限定的指针(基本上是beginend)。 begin 指针用于解除引用/读取,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 对指针的限制,这是否允许?

【问题讨论】:

  • @LPs:我的问题不同。我不想通过别名指针访问同一个对象。 end 指针永远不会被取消引用,并且唯一一次 dataend 别名是当它们相等时(此时取消引用无论如何都是未定义的行为)。我的问题是关于比较两个指针,这是不同的。
  • 显示到建议的副本中,只要您不修改指向的对象,就会定义行为。可能我错过了什么......
  • 注意.end = argv[1] + (argv[1] ? strlen(argv[1]) : 0) 是奇怪的。我期待.end = (argv[1] ? argv[1] + strlen(argv[1]) : argv[1])。您的代码引发了“将 0 添加到 NULL 是否可以”的问题(可能是一个很好的 SO 问题)。建议避免。

标签: c pointers restrict


【解决方案1】:

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

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

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

另外,我不认为Reader.end 必须是restrict-qualified,而且我认为这样的资格对你没有任何帮助。但是,您必须确保既不使用Reader.end 也不使用任何从它派生的指针来访问数据;你必须只使用Reader.data。在main() 中也是如此。 另一方面,如果您无处修改指向的对象,那么几乎所有这些都是没有意义的。

【讨论】:

  • 如果将 restrict 限定的指针与不是从它派生的指针进行比较,clang 和 gcc 都容易表现得毫无意义。我不认为标准中的任何内容旨在允许这种怪异,但我怀疑 clang 或 gcc 的作者是否会允许调整 restrict 的定义以禁止它。
【解决方案2】:

标准或基本原理中没有任何内容暗示任何禁止对限制限定指针进行比较或计算的意图。然而,标准定义一个指针“基于”另一个指针的概念的方式与比较发生了奇怪的交互。例如,给定以下内容:

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 相同的p左值p[i].

【讨论】:

    猜你喜欢
    • 2019-09-08
    • 1970-01-01
    • 2021-04-27
    • 1970-01-01
    • 2013-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-27
    相关资源
    最近更新 更多