본문 바로가기

C_study

[C] 코딩도장 54-55 : 구조체와 공용체 사용하기

1. 구조체와 공용체의 차이점

 

 구조체는 가장 큰 자료형의 배수 크기로 구조체 크기가 선언된다. 이 때 남는 공간은 패딩된다(?).

구조체의 멤버들이 각방을 쓴다면, 공용체의 멤버들은 한 방을 공유한다. 이 때 가장 큰 자료형의 공간을 공유한다.

그렇기 때문에 한 멤버에 값을 저장하면, 나머지 멤버의 값들은 사용할 수 없다. 하지만 한번에 하나씩 값을 저장하고, 사용하면 사용할 수 있다.

#include <stdio.h>

union House {
    int age;
    char person1;
    char person2;
};

int main()
{
    union House house;
    house.age = 12;
    house.person1 = 'c';
    printf("%d\n", house.age); 
    printf("%c", house.person1); // c
    
    return 0;
}

위와 같이 쓰면 이후에 입력된 값만 제대로 출력된다.

#include <stdio.h>

union House {
    int age;
    char person1;
    char person2;
};

int main()
{
    union House house;
    house.age = 12;
    printf("%d\n", house.age); // 12
    house.person1 = 'c';
    printf("%c", house.person1); // c
    
    return 0;
}

위와 같이 쓰면 둘 다 입력된 값이 출력된다.

 

2. 공용체의 저장방식 

#include <stdio.h>

union House {
    int age;
    short num1;
    short num2;
};

int main()
{
    union House house;
    
    house.age = 0x12345678;

    printf("0x%x\n", house.num1); //0x5678

    return 0;
}

대부분의 컴퓨터에서 공용체는 리틀 엔디안 방식으로 메모리에 저장된다. house.age는 int 자료형이므로 4바이트 크기이다. 이 때 리틀 엔디안 방식으로 저장되면 1바이트씩 나뉘어 낮은 자릿수가 앞에 오게 된다. 78 56 34 12 와 같은 형태로 저장된다. 그럼 값을 가져올 때 house.num1은 short자료형이므로 2바이트 크기만큼 가져온다. 가져올 때는 다시 되돌려서 가져오기 때문에 78 56 이 아니라 56 78이 된다.

 

3. 익명 구조체와 익명 공용체

#include <stdio.h>

struct Human{
    union{
        int man;
        struct {
            char age;
            char num1;
            char num2;
            char num3;
        };
    };
};

int main()
{
    struct Human house;
    
    house.age = 0x01;
    house.num1 = 0x02;
    house.num2 = 0x03;
    house.num3 = 0x04;

    printf("0x%x\n", house.man); //0x4030201

    return 0;
}

house.age 와 house.man 처럼 멤버에 바로 접근하기 위해 익명 구조체와 익명 공용체를 사용했다. 공용체 안에서

man 과 age, num1, num2, num3 은 같은 메모리를 공유한다. 구조체 안의 멤버들에게 값을 할당하고 house.man을 출력해보면 값이 역순이 되고 합쳐져서 나온다. 이 때 구조체 안에 멤버들을 선언할 때의 순서는 출력값에 영향을 준다. 

메모리에서의 순서가 num3, num2, num1, age 순이어서  04 03 02 01 로 저장이 된다.

반대로 house.man에 0x04030201 를 저장하고 house.age부터 house.num3을 출력해보면 0x01부터 0x04까지 나온다. 

 

공용체를 사용하면서 리틀 엔디안 방식에 의해 저장되므로 바이트 단위로 끊어서 반대로 저장된다는것, 공용체의 멤버들은 메모리를 공유하기 때문에 한번에 한 멤버의 값만 사용할 수 있다는 것을 염두에 두어야겠다.