構造体/ビットフィールド/列挙型

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

// Structure :
//構造体の型の宣言
    //struct タグ //struct は構造体のキーワード、tag は構造体のタグ名 (人為的に与えられたもの)
    //{     // member - list; //{} 内部のメンバーです1 つ以上の構造体の変数。各メンバー変数は独自の型を持ちます。それらの型は必ずしも相互に関連しているわけではなく、同じであることも異なることもあります。 //} variable-list; // variable-list は変数です。リストは次のとおりです     。 1 つまたは複数。{} の後の ';' は//たとえば、学生の記述struct stu //struct stu は構造体のタイプ; stu は構造体のタグ name {     char name[20]; //name     int age; //age     char sex[5]; //性別     char id[20]; //学生番号}s1; //s1 は構造体変数であり、構造体変数を定義する方法ですint main() {     struct stu s2; / / s2 も構造体変数であり、これも構造体変数を定義する別の方法です。s1 と s2 は両方とも構造体変数ですが、s1 がグローバル変数であり、s2 がローカル変数であるという違いがあります。












    0を返します。
}

//特殊な構造体の宣言
    // 構造体を宣言する場合、完全に宣言する必要はありません。例:
//匿名構造体タイプ
    //(同じ匿名構造体タイプは 1 回のみ使用でき、繰り返し使用することはできません)
struct //通常の構造体タイプの宣言と比較すると、struct キーワードのみがあり、構造体タグ名はありません。 (tag )
{     int a;     char b;     float c; }x; //匿名の構造体型変数は構造体型の {} の直後のみ定義可能



//構造体の自己参照
    // 構造体の自己参照とは、構造体に構造体型のメンバーが含まれるのではなく、構造体型へのポインタ (ポインタは構造体型の次のデータを指す) が含まれていることを意味します。
struct Node
{     int data;     struct Node next; //これは間違った書き方です     struct Node* next; //これが正しい書き方です};



//構造体変数の定義と初期化
struct stu
{     char name[15];     int age; }; struct stu s = { "zhangsan",25 }; // s は定義された構造体変数、struct stu はその Type; use { "zhangsan",25 } toInitialize s struct stu s2 = { .age = 25,.name = "zhangsan"}; //構造体の初期化はメンバーの順序でも行うことができますが、構造体のメンバーが必要です Access 演算子 ' .' struct Nodeを初期化する{     int data;     struct stu a;     struct Node* next; }n1 = { 20,{"lisi",23},NULL }; // 構造体のネストされた初期化: n1 は構造体変数、struct Nodeは n1 のタイプです; struct Node n2 = { 18,{"wangwu",24},NULL };











//構造体のメモリ アライメント(構造体サイズを計算するための重要な知識ポイント)
    // 構造体のメモリ アライメントは、時間 (プロセッサがアライメントされたメモリにアクセスするとき、必要なのはメモリ アクセスを 1 回行うだけです。整列されていないものは 2 回アクセスする必要があります) 
    //スペースを節約し、メモリの無駄を減らすために、構造体の小さなメモリ スペースを占有するメンバ変数をまとめて保持するようにしてください。次の構造体 s1 と構造体 s2: メンバーは同じですが、構造体のサイズが異なります。
    //構造体のアラインメント規則:
        //1. 最初のメンバーは、からのオフセット 0 のアドレスにあります。構造体変数。オフセット: 開始位置との相対的な位置の差を指し、最初のメンバーは開始位置に配置されるため、オフセットは 0 //
        2 です。他のメンバー変数は特定の数に揃える必要があります (アライメントが指定されているアドレス)数値の整数倍)。
            //アライメント番号: コンパイラのデフォルトのアライメント番号 (VS のデフォルト値は 8) とメンバー サイズの小さい値 (例: int 型のサイズは 4 バイト、char 型のサイズは 1 バイト) (単位はバイト) 。
            // 例:
                // 構造体の最初のメンバーが char 型の場合、最初のメンバーはオフセット 0 に配置され、1 バイトを占有します
                // 2 番目のメンバーは int 型で、サイズは 4 バイトであり、VS のデフォルト値である 8 よりも小さいため、int 型のアライメント数は 4 であるため、この int 型メンバーはアライメントする必要があります (配置される) ) オフセット 4 の倍数では、オフセット 0 の後に、オフセット 1、2、および 3 を持つ 3 バイトがあり、これらは 4 の倍数ではありません。この int メンバーは格納できません (オフセット 1、2、および 3 のバイト) 3 は無駄になる) ため、この int 型メンバーは、オフセット 4、5、6、および 7 の 4 バイトである 4 バイトを占有する、オフセット 4 にのみ整列 (配置) できます。 //3.
        合計構造体のサイズは、最大アライメント数 (すべてのメンバー変数の最大アライメント数を指します) の整数倍です。
            //例: 構造体に 4 つのメンバーがあり、それぞれのアライメント番号が 1、4、2、および 8 の場合、最大アライメント番号は 8 です。 // 4 つのメンバーすべてがアライメントされた後の最後の位置がオフセットです
            。 32 バイト、つまり、合計 33 (オフセット 0 からオフセット 32 までの合計 33 バイト) バイトを占有する場合 (途中で無駄になったバイト数を含める必要があります)、その場合、構造体のサイズは次のようになります。最小値は 33 以上で 8 の倍数です、つまり、構造体のサイズは 40 バイトです
        //4。構造体がネストされている場合、ネストされた構造体のアライメント番号は、その構造体のすべてのアライメント番号です。独自のメンバー変数、アライメント数の最大値、構造全体のサイズの計算ルールは変更されません。
struct s1
{     char c1; //アライメント番号: 1、オフセット 0 に位置合わせ、1 バイトを占有: オフセット 0 で 1 バイト     int i; //アライメント番号: 4、オフセット 4 に位置合わせ、4 バイトを占有 バイト: オフセットで 4 バイト4、5、6、および 7 (オフセット 1、2、および 3 の 3 バイトが無駄になります)


    char c2; //アライメント番号: 1、オフセット 5 に位置合わせ、1 バイトを占有: オフセット 8 で 1 バイト
};
struct s2
{     char c1; //アライメント番号: 1、オフセット 0 に位置合わせ、1 バイトを占有 1 バイト:オフセット 0 のバイト     char c2; //アライメント番号: 1 オフセット 1 に整列 1 バイト: オフセット 1 のバイト     int i; //アライメント番号: 4 オフセット 4 に整列され、4 バイトを占有します: fourオフセット 4、5、6、および 7 のバイト (オフセット 2 と 3 の 2 バイトは無駄になります) } ; struct s3 {     double d; //アライメント番号: 8、オフセット 0 に位置合わせ、8 バイトを占有: オフセット付き 8 バイト0, 1, 2, 3, 4, 5, 6, 7     char c; / /アライメント番号: 1 オフセット 8 へのアライメントは 1 バイトを占有します: オフセット 8 はバイト     int i; //アライメント番号: 4 オフセット 12 へのアライメント4 バイトを占有: オフセットは 12、13、14、および 15 の 4 バイト (オフセット 9、10、および 11 の 3 バイトは無駄になります) }; struct s4 {     char c1; //アライメント番号: 1 がオフセット 0 に整列されます。オフセット 0 に 1 バイト













    struct s3 s; //アライメント番号: 8。オフセット 8 へのアライメントは 16 バイトを占有します: オフセット 8 ~ 16 バイト オフセット 23 (オフセット 1、2、3 、4、5、6、および 7 の 7 バイトは無駄になります)
        / /構造体が別の構造体のメンバ変数としてネストされている場合、ネストされた構造体のアライメント番号はすべて自身のメンバ変数になります アライメント番号の最大値 double d; //アライメント番号: 8 オフセット 24 へのアライメントが 8 個を占め
    ますバイト: オフセット 24、25、26、27、28、29、30、31 の 8 ワードセクション
};
int main()
{     printf("%d\n", sizeof(struct s1)); //12                 //メンバ変数のアライメント数は 1、4、1 最大アライメント数:メモリアライメントされた 4 個のメンバ変数は合計 9 バイトを占有(オフセット:0 ~ 8) 条件を満たす最小値は 9 以上4 の倍数 (最大アライメント数): 12 printf(     "%d\n", sizeof(struct s2)) ; //8         //メンバー変数のアライメント数は 1、1、4 です。最大アライメント数は次のとおりです。 4. メモリアライメントされたメンバ変数は合計 8 バイト(オフセット:0 ~ 7)を占有し、8 以上で 4 を満たす (最大アライメント数)の最小倍数:8


    

    printf("%d\n", sizeof(struct s3)); //16
        //メンバー変数のアライメント数は 8、1、4 です。最大アライメント数は 8 です。メモリにアライメントされたメンバー変数は合計を占めます。 16バイト(オフセット:0~15) 8の倍数を満たす16以上の最小値(最大アライメント数):16

    printf("%d\n", sizeof(struct s4)); //32
        //メンバー変数のアライメント数は 1、8、8 です。最大アライメント数は 8 です。メモリアライメントされたメンバー変数は合計を占めます。 32バイトの値(オフセット:0~31) 8の倍数を満たす32以上の最小値(最大アライメント数):32

    0を返します。
}

//デフォルトのアライメント番号を変更する
    // 構造体のアライメントが不適切な場合、デフォルトのアライメント番号を自分で変更できます: #pragma 前処理命令を使用します
struct s1
{     char c1; // アライメント番号: 1 をオフセット 0 にアライメントします。 byte: オフセット 0 のバイト     int i; //アライメント番号: 4、オフセット 4 に位置合わせ、4 バイトを占有: 4 バイト、オフセット 4、5、6、および 7     char c2; //アライメント番号: 1、1 バイトaligned to offset 8: one byte at offset 8 }; #pragma Pack(1) //デフォルトのアライメント番号を 1 に設定します。#pragma Pack(1) は、デフォルトのアライメント番号を変更するために構造体の前に記述されますstruct s2 {     char c1; //アライメント番号: 1、オフセット 0 に位置合わせ、1 バイトを占有: オフセット 0 に 1 バイト     int i ; //アライメント数値: 1、オフセット 1 に位置合わせし、4 バイトを占有: 4 バイト     char c2オフセット 1、2、3、4}; # pragma Pack() //#pragma Pack()は、設定されているデフォルトのアライメント番号をキャンセルし、システムのデフォルトに戻す構造の後に記述されます。












int main()
{     printf("%d\n", sizeof(struct s1));     //メンバ変数のアライメント番号は 1、4、1 です。最大アライメント番号は 4 です。メモリ アライメントされたメンバ変数は、合計9バイト(オフセット:0~8) 9以上で4の倍数を満たす最小値(最大アライメント数):12 printf("%     d\n", sizeof(struct s2)) ;     //メンバ変数 アライメント番号は 1, 1, 1 最大アライメント数は 1 メモリアライメントされたメンバ変数は合計 6 バイトを占有します (オフセット: 0 ~ 5) 1 を満たす最小の倍数 (最大アライメント番号) は 6 以上です。値: 6     return 0; }





//構造体パラメータの受け渡し
    // 構造体パラメータの受け渡し: 変数とアドレスを渡すことでも同じ効果が得られますが、通常は構造体の方が大きくなります。構造体変数を渡す場合、パラメータをスタックにプッシュするシステムのオーバーヘッドが大きくなり、パフォーマンスが低下します。劣化しており、ポインタのサイズは 4 バイトまたは 8 バイトのいずれかです。したがって、構造体のパラメーターを渡すとき は、システムの     オーバーヘッドを減らすために構造
体の     アドレスを渡すことが最善です。,100}; void print1(struct s s1) {     printf("%d\n", s1.num); } void print2(struct s* s1) {     printf("%d\n", s1->num) ; } int main( ) {     print1(s1); //100     print2(&s1); //100     return 0; }



















//ビット セグメント
//ビット セグメントとは
    // ビット セグメント内のビットはバイナリ ビット (ビット ビット) を指します
    // ビット セグメントの宣言は構造と似ていますが、2 つの違いがあります。
        //1 . ビット セグメントのメンバーは、int、unsigned int、signed int、または char (整数ファミリーに属する) である必要があります
        //2. ビット フィールドのメンバーの後には、コロンと数字 (メモリ空間のサイズ) が続きます。メンバー変数、単位はビット (バイナリビットなど))
struct A
{     int a : 5;     int b : 10;     int c : 7;     int d : 28; }; // サイズは 50 ビットint main() {     printf("%d\n" , sizeof(struct A)); //8 (単位はバイト) sizeof の単位はバイトです         //50 ビットに適合するには 7 バイトしか必要ないのに、8 と表示されるのはなぜですか? 具体的な理由については、次のメモリ割り当て     return 0;を参照してください










//ビット セグメントのメモリ割り当て
    // ビット セグメントの空間は必要に応じて 4 バイト (int) または 1 バイト (char) で開かれます
    // VS でビット セグメントに割り当てられたメモリ ビットは右から順に使用されますleft (異なるプラットフォームには異なるメソッドがあります)。残りのビットが十分でない場合、それらは無駄になり、必要な方法 (4 バイトまたは 1 バイト) で新しいビットが開かれます。スペース //ビット セグメントは、構造体およびビット セグメントと同じ効果を達成できます
    。多くのスペースを節約できますが、ビット セグメントには多くのクロスプラットフォームの問題があるため、移植可能なプログラムではビット セグメントの使用を     避ける     必要     あり
ます     。}; //サイズは50ビットですint main() {     printf("%d\n", sizeof(struct A)); //8(単位はワードセクション) sizeofの単位はバイトです         //サイズは計算したビットフィールド構造体 A は 50 ビットで、ビットフィールド構造体 A の空間は 4 バイト (int) 空きます。4 バイトでは足りない場合は 4 バイト空きますので、 sizeof(struct A) 4 の倍数である必要があり、     0 を返します; }












//列挙型
    // 列挙型は、名前が示すように、取り得る値を 1 つずつ列挙することです
//列挙型の定義
enum Sex//enum Sex 列挙型
{     MALE,     FEMALE,     SECRET }; enum Color// enum Color 列挙型{     RED,     GREEN,     BLUE };     // 上記で定義された enum Sex と enum Color はどちらも列挙型です。{} 内の内容は、列挙型の可能な値であり、列挙定数とも呼ばれます。これらの列挙定数はすべてデフォルトでは 0 から始まり、一度に 1 ずつ増加する値を持ちます。     //もちろん、定義時に列挙定数に初期値を割り当てることもできます: enum Color {     RED=1,     GREEN=3,     BLUE=5 };     //一部の列挙定数には初期値が割り当てられます: int main () {     enum Day     {         月、         火、

























        水 = 6、
        木、
        金、
        土 = 20、
        日
    };
    enum Day enum1 = 月;
    enum Day enum2 = 火;
    enum Day enum3 = 水;
    enum Day enum4 = 木; enum Day enum5
    = 金;
    enum Day enum6 = 土;
    enum 日 enum7 = 日;
    printf("%d %d %d %d %d %d %d\n", enum1, enum2, enum3, enum4, enum5, enum6, enum7); //0 1 6 7 8 20 21
    return 0;
}
    //初期化された列挙定数と初期化された列挙定数の両方を含む場合:最初の初期化された列挙定数より前のすべての未割り当ての初期値列挙定数の値は0から始まるデフォルトの規則に従いますand increment by 1;
    //初期値が割り当てられた列挙定数の後の未割り当ての列挙定数の値は、割り当てられた初期値の列挙定数の値に基づきます。

//列挙型の利点
    //1. コードの可読性と保守性が向上します
    //2. #define で定義された識別子定数と比較して、列挙型には型チェックがあり、より厳密です
    //3. デバッグが簡単
    / /4. 簡単に使用すると、複数の定数を一度に定義できます

//列挙型の使用
    // 列挙型定数は列挙型変数に値を割り当てる場合にのみ使用できます。これにより、型の違いがなくなります。列挙型変数に値を割り当てるために純粋な数値を使用することはできません
enum Color
{     RED=1,     GREEN=3,     BLUE=5 }; enum Color clr = BLUE; //clr は enum Color 型の列挙型変数です。列挙定数 BLUE 列挙変数 clr に値を代入します。




おすすめ

転載: blog.csdn.net/libj2023/article/details/131521665
おすすめ