浅いものから深いものへ->C言語のtypedefキーワードの古典的な問題分析

11233 ワード

引用:このシリーズの第3の文章は、一人でも利益を得ることができて、私が分かち合う目的を達成しました!
文章ガイドの魅惑的な登場typedefの基礎遊び方typedefの進級遊び方(各種奇抜な声明)typedef.VS. #define
本文
一、魅惑的な出番
~~~~~~~~~C言語にはいつも字面的に困っているキーワードが存在しますが、typedefも例外ではありません.実際、typedefは既存のデータ型の名前を変更するしかなく、本質的に新しいタイプを生成することはできません.注意:値ではなくタイプを対象としている点は、#defineとは異なります.真相はすでに明らかになって、C言語の創造者は淡々と笑って、本当に私の鍋ではありません!
二、typedefの基礎遊び方
~~~~~~~~~ここではtypedefキーワードの簡単な使い方を紹介しますが、これも後続のステップアップの敷居として使われています.
typedef int Int32;

struct _tag_test
{
	int x;
	int y;
}typedef struct _tag_test Test; //          

typedef struct
{
	int len;
	int array[];
} SoftArray; //struct     ,         

typedef struct _tag_list_node ListNode; //          
struct _tag_list_node
{
	ListNode * next; //       
};

int main()
{
	Int32 i = -100; //int
	//unsigned Int32 j = 0; //error
	Test t;
	SoftArray * sa = NULL;
	ListNode * node = NULL;
	
	return 0;
}

上の短い例では、2つの有用な結論を掘り起こすことができます.
  • typedefタイプの名前を変更する場合は、既存のタイプの後に、定義するタイプの前に配置できます.もちろん,上述したstruct構造体はC言語では1つのタイプとは言えないが,ひとまずこのように理解してもあまり妥当ではない.
  • は、typedefの名前変更後のタイプをunsignedまたはsignedで修飾することはできません.

  • 三、typedefの進級遊び方
    1.奇抜な声明
    注意:前方の高エネルギーは、安全で快適な環境で細かく読んでください.
    int box[8][8]; //int     
    int ** ptr;  //  int      
    int * ptr[10];  //    ,          int   
    int (*ptr)[10]; //    ,    10    int  
    int * ptr[3][4]; //       ,  ...
    int*ptr[3])[4]; //    ,    3      ,            4    int     。
    char* (*func[3])(char*); //    (3        ),          char*     ,      char*   。
    

    ちょっとめまいがしますか?ははは、実は私は彼らを説明したいわけではありません.私を殴らないでください.まず、次のルールについて説明します.
    ポインタ()を表す関数[]は配列[]を表し、()は間接演算子*よりも優先されます.[]と()は左から右に結合されているので、読むときは前後の組み合わせで徐々に剥がさなければならない.
    ~~~~~~~~~最後に最も複雑に見える関数ポインタを例に挙げます.まず、真ん中の位置(*func[3]):[3]はfuncが配列であることを表すが、※番号はポインタであることを示し、マージされた情報はポインタ配列である.次に、ポインタである以上必ず指向があり、さらに右を見るともう一つのカッコ(char※)が発見され、関数として得られる.最後に,中間のfunc部分を隠すと注釈中の結論が得られる.确かに少し回りますが、后の指针の部分の文章は、もっと简単に说明するように努力します.
    2.typedefは簡略化する
    ~~~~~~~~~上のお菓子は可読性が低いように見えますが、確かに、実は簡単な美しさはずっと人々の追求であり、typedefは私たちに美しさを開く機会を与えてくれました.
    (1)配列ポインタ、友達を作ろう!
    typedef type(name)[size]; /*         */
    
    typedef int(AINT5)[5];/*   ,     AINT5        */
    AINT5 a; //   int a[5];
    
    AINT5* pi; //            ,   int (*pi)[5];
    int (*pi)[5]; //        
    

    この小さな例を見て、この中の簡単な調和のとれた美しさを発見したかどうか分かりません.
    (2)関数ポインタ、認識して!
    typedef type (name)(parameter list) /*         */
    
    typedef int (FUN)(int, int); /*   ,     FUN      */
    FUN* ptr; //          ,   int (*ptr)(int, int)
    

    うん、あなたはすでにその妙用を知っていると信じて、あなたも私と同じようにこのような言語の芸術と美感を好きになるかもしれません!
    四、typedef.VS. #define
    ~~~~~~~~~~~~typedefと#defineの違いは、データ型を定義する際に現れ、特にポインタ操作時に現れる.
    (1)例1(基本差)
    typedef char* PCR1;
    #define PCR2  char*
    
    PCR1 s1, s2;
    PCR2 s3, s4;
    

    ~~~~~~~~~この例では、変数s 1,s 2,s 3はchar*タイプとして定義され、s 4のみがcharとして定義される.この違いの根本的な原因は、#defineは単純なテキスト置換にすぎず、typedefは新しいタイプ名に相当する.
    (2)例2(深層掘削)
    typedef char* p_str;
    char str[] = "abc";
    const char* p1 = str;
    const p_str p2 = str;
    p1++;
    p2++;
    

    ~~~~~~~~~上記のコードには隠れたエラーがあります(コンパイラはp 2++エラーを提示します).この問題は、typedefと#defineの違い、すなわち簡単なテキスト置換ではないことを改めて示唆している.実はconst p_str p 2はconst char*p 2に等しくない(内包的に言えば)、const p_str p 2とconst long xには本質的な違いはなく,いずれも変数に読み取り専用属性を与える.ただし、上記の例の変数p 2のデータ型は、システム固有のタイプではなく、私たちのtypedefが出てくるタイプです.したがってconst p_str p 2は、データ型をcharに限定する変数が読み取り専用であることを意味する(charはintのような固有のタイプとして理解できる).
    関連資料C Primer Plus高品質埋め込み式Linux Cプログラミングディテソフトウェア学院-C言語進級剖析チュートリアル
    次号予告:C言語の老大難のポインタと配列問題の分析に入ります!