C / C ++のrawポインターと関数ポインターでサポートされる操作は何ですか?

StackOverflow https://stackoverflow.com/questions/1418068

質問

関数ポインタでサポートされるすべての操作は、生のポインタとどのように異なりますか? <!> gt; 、<!> lt; 、<!> lt; =、<!> gt; = rawポインターでサポートされている場合、演算子は何ですか?

役に立ちましたか?

解決

関数ポインターとオブジェクトポインターの両方についてはコンパイルされますが、結果は同じ完全なオブジェクトのサブオブジェクトへのアドレスに対して一貫性があることが保証されます(クラスまたは配列の2つのメンバーのアドレスを比較できます)関数またはオブジェクトをそれ自体と比較します。

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値がないため、指示先タイプの+で定義された操作は機能しません。以下が含まれます。

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.

最後に、関数へのポインター pointer は関数ポインターではないことに注意してください:

void (**pp)() = &p;
// all do work, because `sizeof (void(*)())` is defined.
pp++; pp--; pp + n; pp - n;

他のヒント

ポインタが同じ割り当てを指している場合、ポインタを比較できます。たとえば、同じ配列の要素を指す2つのポインターがある場合、それらのポインターで不等式比較演算子を使用できます。一方、異なるオブジェクトを指す2つのポインターがある場合、比較は<!> quot; undefined <!> quot;ですが、実際には、ほとんどのコンパイラーはおそらくアドレスを比較するだけです。

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

#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; 
}

演算子<!> lt;、<!> gt;、<!> lt; =、<!> gt; =はポインターでサポートされていますが、比較される2つのポインターが同じメモリ割り当ての一部(2つのポインタを配列割り当てのインデックスと比較するなど)。これらの場合、割り当て内の相対位置を示します(つまり、a <!> lt; bの場合、aは配列内のbよりも低いインデックスを指します)。同じ割り当てにないポインターの場合、結果は実装定義になります(一部のアーキテクチャーでは、マップに必要な互換性よりも厳格に違反する可能性があります。たとえば、64ビットポインターは<!> lt;または< !> gt;単一の割り当てが32ビットポインターに許可されているサイズを超えることができない場合、下位32ビットのみを使用します。これらは、連続的なメモリ割り当てに対応していないため、関数ポインタのコンテキストでは実際には意味がありません。

その他の生のポインタ操作:==は、ポインタが同じオブジェクトを指している場合にtrueを返します。 -2つのポインター間のバイト数を生成します(同じ割り当てにのみ適していると思いますか?)。 +は意味がないため、コンパイルしません。

関数ポインタの場合、*によって間接参照され、呼び出されます。

メンバー関数へのポインターには、演算子-<!> gt; *および。*があります

ポインターは通常の整数値として表されます。他のすべての数値型でも許可されているポインターを使用して、すべてを実行できます。 +-* / <!> lt; <!> lt; <!> gt; <!> gt; ==!= ^ <!> amp; | ! 〜%。何も忘れなかったことを願っています。

関数ポインタは、()演算子で呼び出すことができるという点でのみ異なります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top