1

"str"or&"str"[0]を取り&"str"、同じポインタを異なるタイプで取得すると、私が何を意味するかがわかります。

注: 文字列リテラルが区別されないシステムを使用しています。

printf("%p\n", "str");
printf("%p\n", &"str"[0]);
printf("%p\n", &"str");

// hypothetical output:
// 0xADD12E550  (ptr to char)
// 0xADD12E550  (ptr to char)
// 0xADD12E550  (ptr to arr of char)

したがって、理論的には、 を&"str"逆参照すると、同じポインターを逆参照しているため、文字列の最初の文字を取得できるはずです。奇妙なことに、そうではありません。2 回逆参照する必要があります。配列を取得するために一度、次に最初の文字定数を取得するためにもう一度:

// &"str" = 0xADD12E550
// *(0xADD12E550) = 0xADD12E550
// *(0xADD12E550) = 's'

// **(&"str") == 's'

たぶん、この質問はこれがどのように可能であるかにも答えることができます:

#include <stdio.h>

void dafunk() {
  printf("dadftendirekt\n");
}

main() {
  void (*dafunkptr)() = dafunk;
  (***************dafunkptr)();

  return 0;
}
4

2 に答える 2

3

オブジェクト"str"は、の配列4型ですchar

の値"str"は、へのポインタ型charです。

の値&"str"[0]は、へのポインタ型charです。

の値は &"str"、の配列4へのポインタ型ですchar

編集

したがって、たとえば文字列の最初の文字にアクセスするには"str"、式を一度逆参照する必要があります。

char s = *"str";  // or s = "str"[0] 

または、式&"str"の型が配列へのポインタであるため、式から式を2回逆参照する必要があります。

char s = **&"str";   // or s = *(&"str")[0]
于 2012-04-08T23:54:38.520 に答える
1

"str"のタイプはchar[4]です。(C++ では、 になりますconst char[4]。)

配列型の式は、ほとんどのコンテキストで、配列オブジェクトの最初の要素へのポインターに暗黙的に変換されます。この変換は、一般に「減衰」と呼ばれます。これに対する例外は次のとおりです。

  • 単項演算子のオペランドの場合sizeof(sizeof "str"は、ポインターのサイズではなく、配列のサイズを生成します)。
  • それが単項演算子のオペランドである場合&(ではなく&"str"type の結果が得られます)。char(*)[4]char*
  • 配列オブジェクトの初期化に使用される初期化子の文字列リテラルの場合 (ここでは適用されません)。

これら 3 つのケースでは、配列式はその配列型を保持します。

文字列リテラルは、リテラルの文字と終端の'\0'null 文字を保持するのに十分な大きさの、静的記憶域期間を持つ暗黙的に作成された配列オブジェクトを参照します。この場合、"str"はタイプ の匿名静的オブジェクトを参照しますchar[4]

そう:

printf("%p\n", "str");

"str"のをchar*指す値に暗黙的に変換されます。's'"str"

printf("%p\n", &"str"[0]);

上記のように、 "str"in は に"str"[0]減衰しchar*ます。 を指す値を"str"[0"生成します。したがって、 とは同じ型と値です。char*'s'"str""str"[0]

printf("%p\n", &"str");

ここで、"str"は のオペランドである&ため、減衰は発生しないため&"str"、匿名char[4]オブジェクトの最初の文字のアドレスではなく、そのアドレスが生成されます。この式は、タイプchar(*)[4]、または「4 文字の配列へのポインタ」です。

&"str"[0]&"str"両方がポインター値を生成します。どちらもメモリ内の同じ場所を指しますが、型は異なります。

3 つのケースすべてで、式の評価結果が引数として に渡されますprintfprintfwith "%p"format には type の引数が必要void*です。最初の 2 つのケースでは、 を渡しておりchar*、 と に対する言語の要件は、それが期待どおりに機能することchar*void*暗示しています。char*3 番目のケースでは、 vs.にはそのようなルールがないchar(*)[4]ため、 の動作は

printf("%p\n", &"str");

未定義です。

たまたま、ほとんどの実装では、すべてのポインター型が同じサイズと表現を持っているため、任意の型のポインターを with に渡しても問題ありませprintf"%p"

void*3 つのケースすべてで、未定義の動作を回避して、式を に明示的にキャストできます (おそらくそうすべきです) 。

printf("%p\n", (void*)"str");
printf("%p\n", (void*)&"str"[0]);
printf("%p\n", (void*)&"str");

質問の 2 番目の部分では、明確な問題を扱います。関数へのポインタについてです。ポインター型の式の規則は、配列型の規則と似ています。関数型 (関数名など) の式は、sizeof(不正な) または&(のオペランドである場合を除き、関数へのポインターに暗黙的に変換されます。関数のアドレスを生成します)。そのため、関数への*orの適用&はノーオペレーションのように機能します。では*funcfunc最初に関数へのポインターに減衰し、ポインターを*逆参照し、結果が再び関数へのポインターに減衰します。では&func、は減衰を抑制しますが、それ自体が生成&する関数への同じポインターを生成します。func

于 2012-04-09T01:09:27.347 に答える