[C言語]#6構造体、共通体


なぜ構造体を使うのですか?
  • 人類の理解を助ける.
  • コンピュータは構造体の概念を知らない(単純に複数の領域変数を組み合わせて使用するだけ)
  • .
  • パラメータ列には複数の名前があるため、エラーを減らすことができます.(一つ抜けたり、順番を逆さまにしたり…)
  • typedeftypedefは、構造体において他のタイプと同様に簡潔に変数を宣言することができる(共通タイプおよび列挙タイプも同様であることができる).
    // 사용법 1
    struct date{
        int year;
        int month;
        int day;
    };
    typedef struct date date_t;
    
    // 사용법 2
    typedef struct date{
        ...
    } date_t;
    
    // 사용법 3
    typedef struct {
        ...
    } date_t;
    
    
    date_t date;
    
    date.year = 2022;
    date.month = 10;
    date.day = 1;
    構造体メンバー変数へのアクセス
    /* 매개변수가 포인터(주소값이라면) */
    -> // 포인터의 값에 접근해서 멤버변수 가져오기
    date->year
        
    /* 매개변수가 구조체(값이라면) */
    . // 구조체의 멤버변수 가져오기
    (*date).year
    構造パラメータの最適値
    データのサイズがソースを変更しない場合、構造体をアドレスに転送することは非常に有効です.

  • 基本データ型は、元のデータが変更されたときにアドレスに送信するだけです.

  • 転送先が原本を変更する恐れがある場合は、constキーワードを使用してください.
  • パラメータが10個程度の場合は、構造体に変更して渡すことが望ましい.
    構造体使用時のポインタの保存

  • 次の構造変数を導入すると、内部で何が起こりますか?
  • typedef struct {
        char* firstname;
        char* lastname;
    } name_t;
    
    name_t name;
    
    char [] firstname = "Lee";
    char [] lastname = "lulu";
    
    name.firstname = firstname;		// firstname은 포인터 변수 : firstname의 주소값을 저장
    name.lastname = lastname;		// lastname은 포인터 변수 : lastname의 주소값을 저장
    
    name_t clone = name;			// clone.firstname 공간에 name.firstname의 값(주소값)들어간다
    clone.firstname[0] = 'Q';		// 복사본, 원본 모두 바뀐다. firstname 변수 값 자체도 바뀐다.
    printf("%s / %s / %s", clone.firstname, firstname, name.firstname);


  • 浅い放射
  • コピーは、元のデータのアドレス値
  • を指す.
  • コピーの値を変更すると、元のアドレスに値が変更されるため、元の値も変更されます.

  • ふかほうしゃ
  • 既存のすべてのデータを新しいメモリ領域
  • にコピー
  • コピーのデータを変更しても、元のデータは変更されません.
  • ポインタ変数のない構造体
    NAME_LEN = 32;
    typedef struct {
    	char firstname[NAME_LEN];
        char lastname[NAME_LEN];
    } name_t;
    
    void check_size (name_t name){
        size_t size;
        size = sizeof(name);		// size:64
        // --> 원본의 크기 그대로 함수의 매개변수가 전달된다.
    }
  • 元のアレイを関数パラメータとして伝達し、アレイの初期位置のアドレス値のみを伝達し、
  • 元のアレイを関数パラメータとして伝達する.
  • 構造体として配列されたメンバー変数を使用して、構造体を関数因子として渡し、配列サイズに従ってコピーします.
  • 関数の内部に構造体を作成して戻り値として使用すると、呼び出し元(他のデータ型と同じ)
  • に値が直接コピーされます.
  • つまり、構造体に針がなければ・・・代入だけですべてを完璧にコピーできます.
  • 構造体は、できるだけポインタ変数がないことが望ましい.
  • バイトソート
    typedef struct {
    	unsigned int id;			// 4바이트
    	name_t name;				// 64바이트
    	unsigned short height;		// 2바이트
    	float weight;				// 4바이트
    	unsigned short age;			// 2바이트
    } user_info_t;					// 76바이트?
    // 실제 크기는 80byte
    
    // 실제 차지하고 있는 메모리 구하기.
    user_info_t info;
    int off_id = (char*)&info.id - (char*)&info;		// 0
    int off_name = (char*)&info.name - (char*)&info;	// 64
    int off_height = (char*)&info.name - (char*)&info;	// 68	?
    int off_weight = (char*)&info.name - (char*)&info;	// 72
    int off_age = (char*)&info.name - (char*)&info;	// 76

  • 2 byteのshort資料型が4 byteの空間を占めていた.

  • 各システムには、データを読み出す単位があります.

  • x 86システムは、4バイト(フォント)境界から効率的に読み取ることができる

  • コンパイラは自分で設定し、残りの2バイトのスペースを無視して4バイト(塗りつぶし)を使用します.

  • 問題は、他のアーキテクチャシステムから異なる方法で読み込まれた場合...データが破壊され、正常に使用できない可能性があります.

  • 方法は.

  • プログラマを4バイト順に切り捨てます-->2つの短い変数を順番に保存します
  • 4バイト、使用しないバイトは構造体に含む(ex char unused[2];)
  • assert()を使用してサイズを決定
  • #include <assert.h>
    assert(sizeof(user_info_t) == 76);
  • ビットフィールド
    バイト単位ではなくビット単位でデータ型を作成する場合は、
    typedef struct {
    	unsigned char b0 : 1;
        unsigned char b1 : 1;
        unsigned char b2 : 1;
        unsigned char b3 : 1;
        unsigned char b4 : 1;
        unsigned char b5 : 1;
        unsigned char b6 : 1;
        unsigned char b7 : 1;
    } bitflags_t;
    // size : 1 (1바이트 : 8비트)
    ポインタで一度比較できます(小細工...本来は共通のはずです)
    char* val;
    int is_zero;
    bitflags_t flas = {0, };
    
    flags.b3 = 1;
    
    val = (char*)&flags; 	// flags를 1바이트 단위로 읽는 포인터 val
    is_zero = (*val == 0);	// val의 값이 0이면 모든 비트플래그가 0
    コモンボディ
    異なる変数を使用して同じメモリ位置にアクセスする方法(共通コンテナ内の複数の変数が同じメモリを共有する)
    同じメモリを様々な変数で読み込む方法!
    typedef union {
    	unsigned char val;
    	struct {
    		unsigned char b0 : 1;
            unsigned char b1 : 1;
            unsigned char b2 : 1;
            unsigned char b3 : 1;
            unsigned char b4 : 1;
            unsigned char b5 : 1;
            unsigned char b6 : 1;
            unsigned char b7 : 1;
    	} bits;
    } bitflags_t;
  • 変数valと構造体bitsは同じアドレスを指します!(両方ともポインタ)
  • 上に針で作ったものは公用体にすることができます.
    int is_same;
    int is_zero;
    bitflags_t flags = {0, };
    
    flags.bits.b1 = 1;
    flags.bits.b4 = 1;
    
    is_same = (flags.bits.b1 == flags.bits.b7);
    is_zero = (flags.val == 0);
    共通エンティティの使用例(カラー表示)
    typedef union {
        unsigned int val;
        struct {
            unsigned char r;
            unsigned char g;
            unsigned char b;
            unsigned char a;	// 투명도 00 ~ FF (불투명)
        } rgba;
    } color_t;