6

函数指针支持的所有操作与原始指针有什么不同?> , < , <= , >= 操作符是否受原始指针支持,如果有,有什么用?

4

5 回答 5

14

对于函数和对象指针,它们都可以编译,但它们的结果仅保证对于同一完整对象的子对象的地址是一致的(您可以比较一个类或数组的两个成员的地址),如果您比较一个函数或反对自己。

使用std::less<>,std::greater<>等等将适用于任何指针类型,并且将给出一致的结果,即使相应的内置运算符的结果未指定:

void f() { }
void g() { }

int main() {
  int a, b;

  ///// not guaranteed to pass
  assert((&a < &b) == (&a < &b));

  ///// guaranteed to pass
  std::less<int*> lss1;
  assert(lss1(&a, &b) == lss1(&a, &b));
  // note: we don't know whether lss1(&a, &b) is true or false. 
  //       But it's either always true or always false. 

  ////// guaranteed to pass
  int c[2];
  assert((&c[0] < &c[1]) == (&c[0] < &c[1]));
  // in addition, the smaller index compares less:
  assert(&c[0] < &c[1]);

  ///// not guaranteed to pass
  assert((&f < &g) == (&f < &g));

  ///// guaranteed to pass
  assert((&g < &g) == (&g < &g));
  // in addition, a function compares not less against itself. 
  assert(!(&g < &g));

  ///// guaranteed to pass
  std::less<void(*)()> lss2;
  assert(lss2(&f, &g) == lss2(&f, &g));
  // note: same, we don't know whether lss2(&f, &g) is true or false.

  ///// guaranteed to pass
  struct test {
    int a;
  // no "access:" thing may be between these!
    int b;

    int c[1];
  // likewise here
    int d[1];

    test() {
      assert((&a < &b) == (&a < &b));
      assert((&c[0] < &d[0]) == (&c[0] < &d[0]));

      // in addition, the previous member compares less:
      assert((&a < &b) && (&c[0] < &d[0]));
    }
  } t;
}

所有这些都应该编译(尽管编译器可以自由地警告它想要的任何代码片段)。


由于函数类型没有sizeof值,根据指针类型定义的操作sizeof将不起作用,这些包括:

void(*p)() = ...;
// all won't work, since `sizeof (void())` won't work.
// GCC has an extension that treats it as 1 byte, though.
p++; p--; p + n; p - n; 

一元+适用于任何指针类型,并且只会返回它的值,对于函数指针没有什么特别之处。

+ p; // works. the result is the address stored in p.

最后请注意,指向函数指针的指针不再是函数指针:

void (**pp)() = &p;
// all do work, because `sizeof (void(*)())` is defined.
pp++; pp--; pp + n; pp - n;
于 2009-09-13T16:35:13.850 回答
2

如果指针指向相同的分配,您可以比较它们。例如,如果有两个指针指向同一个数组的元素,则可以对这些指针使用不等比较运算符。另一方面,如果您有两个指向不同对象的指针,那么比较是“未定义的”,但实际上,大多数编译器可能只会比较地址。

char *text[] = "hello";
const char *e_ptr = strchr(text, 'e');
const char *o_ptr = strchr(text, 'o');
if (e_ptr < o_ptr) { ... }  // this is legal
char *other_text[] = "goodbye";
const char *b_ptr = strchr(other_text, 'b');
if (b_ptr > o_ptr) { ... }  // not strictly legal
于 2009-09-13T16:16:22.807 回答
1

#1:可以调用函数指针。

#2:指针支持关系运算符,因为您可以在指针算术中使用它们并相互比较地址。实际示例:遍历数组

int data[5] = { 1, 2, 3, 4, 5 };

// Increment pointer until it reaches the end-address. 
for (int* i = data; i < data + 5; ++i) {
    std::cout << *i << endl; 
}
于 2009-09-13T16:12:01.583 回答
1

操作符 <、>、<=、>= 支持指针,但只有在被比较的两个指针是同一内存分配的一部分时才能保证产生可靠的结果(例如比较两个指针到数组分配中的索引)。对于这些,它表示分配中的相对位置(即,如果 a < b,则 a 指向数组中比 b 低的索引)。对于不在同一分配中的指针,结果是实现定义的(并且在某些体系结构中,可能违反严格小于映射所需的兼容性。例如,可以仅使用较低的值来比较 < 或 > 的 64 位指针32 位,如果单个分配不能超过 32 位指针所允许的大小)。这些在函数指针的上下文中没有意义,因为它们没有

其他原始指针操作:== 如果指针指向同一个对象,则返回 true。- 产生两个指针之间的字节数(我认为只适用于相同的分配?)。+ 不编译,因为它没有意义。

对于函数指针,它们可以被 * 取消引用并被调用。

对于指向成员函数的指针,有运算符 ->* 和 .*

于 2009-09-13T16:21:42.940 回答
0

指针表示为普通整数值。你可以用指针来做所有事情,这在所有其他数字类型上也是允许的。+ - * / << >> == != ^ & | !〜%。我希望我什么都没忘记。

函数指针的不同之处仅在于它可以使用 () 运算符调用。

于 2009-09-13T23:19:59.817 回答