web-dev-qa-db-ja.com

「typedef」の構文規則とスコープについて説明してください

ルールは何ですか? OTOH単純なケースは、新しいタイプが行の最後のものであることを暗示しているようです。ここのようにUcharは新しいタイプです:

typedef unsigned char Uchar;

しかし、関数ポインタは完全に異なります。ここで、新しいタイプはpFuncです。

typedef int (*pFunc)(int);

他の例をすぐに思いつくことはできませんが、非常に紛らわしい使用法に出くわしました。

それで、ルールはありますか、それとも人々はこれが以前にこのように行われたのを見たので、これがどのように行われるかを経験から知っているはずですか?

また:typedefの範囲は何ですか?

34
ValenceElectron

基本的に、typedefの構文はオブジェクト宣言とまったく同じですが、接頭辞としてtypedefが付いており、新しい識別子がオブジェクトの型のエイリアスを宣言するように意味が変更されています。それが通常の宣言であったならば、宣言されていたでしょう。

typedefは、オブジェクト宣言とまったく同じスコープであるため、ファイルスコープであるか、ブロックに対してローカルであるか、(C++では)名前空間またはクラスに対してローカルである可能性があります。

例えば.

intを宣言します:

int a;

intのエイリアスであるタイプを宣言します。

typedef int a_type;

charへのポインタを宣言します:

char *p;

char *のエイリアスを宣言します:

typedef char *pChar;

関数ポインタを宣言します:

int (*pFn)(int);

'intを受け取りintを返す関数へのポインタである型のエイリアスを宣言します。

typedef int (*pFunc)(int);
65
CB Bailey

構文上の便宜のために、typedefは、externstatic、またはregisterのように、ストレージクラス指定子として扱われます。意味的にはもちろんまったく異なりますが、typedefが言語に追加されたときは、既存の文法を使用して構文を定義する方が簡単でした。

オブジェクト宣言にstaticを追加しても、オブジェクトのストレージクラスが「静的」に変更される(そうでない場合)ことを除いて、宣言の意味は変更されません tすでに):

{
    int foo; /* automatic storage duration */
    static int bar; /* static storage duration */
}

statictypedefに置き換えると、宣言の意味が変わり、定義される名前はオブジェクト名ではなくタイプ名(実際には既存のタイプの単なるエイリアス)になります。

    typedef int baz; /* "baz" is an alias for "int" */

同じ構文がより複雑な宣言にも適用されます。

int (*a)[42];         /* a is a pointer to an array of 42 ints */
static int (*b)[42];  /* Same as a, but with static storage duration */
typedef int (*c)[42]  /* c is an alias for the type int(*)[42], or 
                         "pointer to array of 42 ints" */

typedefexternstatic、およびregisterによって占められている文法の同じスロットに任意に押し込まれていることに気付いたら、typedef宣言を理解することは、オブジェクト宣言を理解することよりも難しくありません(そして簡単ではありません!)。 (cdeclプログラムと Webサイト は、複雑な宣言を解凍するのに役立ちます。)

関数タイプにtypedefを設定することもできます。

void func(void);              /* declare func as a function */
typedef void func_type(void); /* declare func_type as a name
                                 for a function type */

typedefed関数タイプを使用して関数を宣言または定義することはできませんが、それを使用して関数ポインターを宣言することはできます。

func_type *ptr = func;

scope(宣言された識別子が表示されるプログラムテキストの領域を意味します)に関しては、typedef宣言によって定義された識別子は他のものと同じスコープを持ちます他の宣言された識別子。関数の外部のファイルスコープで宣言されている場合は、宣言のポイントからファイルの終わりまで表示されます。関数内で宣言されている場合は、宣言されたポイントから最も近い囲んでいるブロックの終わりまで表示されます。また、他の宣言と同様に、内部スコープ内の同じ名前の別の宣言によって非表示にすることができます。

7
Keith Thompson

他の誰もそれについて言及しなかったという理由だけで:それは常に任意のオブジェクトビルドにローカライズされます。したがって、同じusing/typedef名で異なるcppファイルをコンパイルしている場合、それらは互いに影響しません。

0
Elliott