본문 바로가기
C++

[C++] 공용체와 열거체

by teamnova 2024. 6. 9.
728x90

C++는 다양한 데이터 구조를 제공하여 개발자가 데이터를 효율적으로 관리하고 사용할 수 있도록 돕습니다. 그 중에서도 공용체(Union)와 열거체(Enum)는 독특하고 유용한 기능을 제공합니다. 이번 포스팅에서는 공용체와 열거체에 대해 자세히 알아보고, 예제 코드와 실제 개발에서의 사용 사례를 통해 이해를 돕겠습니다.

공용체(Union)

공용체는 하나의 메모리 공간을 여러 데이터 멤버가 공유하는 데이터 구조입니다. 이는 메모리를 절약할 수 있는 장점이 있지만, 동시에 한 번에 하나의 멤버만 사용할 수 있다는 제약이 있습니다. 공용체의 각 멤버는 동일한 메모리 주소를 사용하므로, 마지막에 저장된 값만이 유효합니다.

#include <iostream>
using namespace std;

union Data {
    int intValue;
    float floatValue;
    char charValue;
};

int main() {
    Data data;
    
    data.intValue = 10;
    cout << "intValue: " << data.intValue << endl; // 출력: intValue: 10
    
    data.floatValue = 220.5;
    cout << "floatValue: " << data.floatValue << endl; // 출력: floatValue: 220.5
    cout << "intValue after float assignment: " << data.intValue << endl; // 출력: intValue after float assignment: 1132396544 (부정확한 값)
    
    data.charValue = 'A';
    cout << "charValue: " << data.charValue << endl; // 출력: charValue: A
    cout << "floatValue after char assignment: " << data.floatValue << endl; // 출력: floatValue after char assignment: 3.04261e-43 (부정확한 값)
    
    return 0;
}



위 코드에서 `Data`라는 공용체를 선언하고, `int`, `float`, `char` 타입의 멤버를 정의했습니다. 하나의 멤버에 값을 할당하면 이전에 저장된 값이 덮어써지게 됩니다. 


공용체는 주로 하드웨어 레지스터나 네트워크 패킷 등의 메모리를 효율적으로 관리할 때 사용됩니다. 다음 예제에서는 IPv4 주소를 표현하기 위해 공용체를 사용하여 네 개의 바이트 배열로 IP 주소를 저장하고 출력하는 방법을 보여줍니다.

#include <iostream>
using namespace std;

union IPv4 {
    uint32_t ip;
    uint8_t bytes[4];
};

int main() {
    IPv4 address;
    address.ip = 0xC0A80001; // 192.168.0.1 in hexadecimal
    
    cout << "IP Address: ";
    for (int i = 3; i >= 0; i--) {
        cout << (int)address.bytes[i];
        if (i != 0) cout << ".";
    }
    cout << endl;
    
    return 0;
}



위 코드에서는 `IPv4` 공용체를 사용하여 IP 주소를 네 개의 바이트로 표현하고 있습니다. 이는 네트워크 프로그래밍에서 데이터를 효율적으로 관리하는 데 유용합니다.

열거체(Enum)

열거체는 관련된 상수들의 집합을 정의하는 데 사용됩니다. 이를 통해 코드의 가독성과 유지보수성을 높일 수 있습니다. 열거체를 사용하면 의미 있는 이름을 가진 상수들을 정의할 수 있어 코드의 가독성이 향상됩니다.

#include <iostream>
using namespace std;

enum Color { RED, GREEN, BLUE };

int main() {
    Color color = GREEN;
    
    switch (color) {
        case RED:
            cout << "Color is RED" << endl;
            break;
        case GREEN:
            cout << "Color is GREEN" << endl;
            break;
        case BLUE:
            cout << "Color is BLUE" << endl;
            break;
    }
    
    return 0;
}



위 코드에서 `Color`라는 열거체를 선언하고, `RED`, `GREEN`, `BLUE`라는 상수들을 정의했습니다. `switch` 문을 사용하여 열거체 값을 처리합니다.

열거체는 상태 기계(State Machine)나 다양한 설정 값을 정의할 때 유용하게 사용됩니다. 다음 예제에서는 `State` 열거체를 사용하여 시스템의 상태를 정의하고, 현재 상태에 따라 메시지를 출력하는 함수를 구현했습니다.

#include <iostream>
using namespace std;

enum class State { START, RUNNING, STOPPED };

void printState(State state) {
    switch (state) {
        case State::START:
            cout << "System is starting." << endl;
            break;
        case State::RUNNING:
            cout << "System is running." << endl;
            break;
        case State::STOPPED:
            cout << "System is stopped." << endl;
            break;
    }
}

int main() {
    State currentState = State::START;
    printState(currentState);
    
    currentState = State::RUNNING;
    printState(currentState);
    
    currentState = State::STOPPED;
    printState(currentState);
    
    return 0;
}



위 코드에서는 `State` 열거체를 사용하여 시스템의 상태를 정의하고, `printState` 함수는 열거체 타입에 따라 메시지를 출력합니다.

공용체와 열거체의 차이점과 공통점

차이점
1. 메모리 사용 :
   - 공용체는 여러 멤버가 같은 메모리 공간을 공유하여 메모리 사용이 효율적입니다. 예를 들어, `Data` 공용체의 크기는 가장 큰 멤버의 크기와 같습니다.
   - 열거체는 상수 집합을 정의하며, 메모리 공유와는 관련이 없습니다. 열거체의 크기는 컴파일러와 플랫폼에 따라 다를 수 있으며, 보통 `int` 크기와 비슷합니다.

2. 사용 목적 :
   - 공용체는 주로 메모리 효율성이 필요한 경우에 사용됩니다. 예를 들어, 네트워크 패킷 처리나 하드웨어 레지스터 접근 시 공용체가 유용합니다.
   - 열거체는 관련된 상수들을 그룹화하여 코드의 가독성과 유지보수성을 높이는 데 사용됩니다. 예를 들어, 상태 기계나 다양한 설정 값 정의 시 열거체가 유용합니다.

3. 동작 방식 :
   - 공용체는 하나의 멤버만 활성 상태로 유지될 수 있습니다. 여러 멤버를 동시에 사용할 수 없으며, 마지막에 저장된 값만 유효합니다.
   - 열거체는 명명된 정수 상수의 집합을 정의하며, 특정 상태나 옵션을 표현합니다. 각 상수는 고유의 값을 가지며, 동시에 여러 상수를 사용할 수 있습니다.

공통점
- 둘 다 사용자 정의 데이터 타입을 정의할 수 있습니다.
- 코드의 가독성과 유지보수성을 높이는 데 기여합니다.

다음은 공용체와 열거체를 함께 사용하는 예제입니다. 여기서는 공용체를 사용하여 메모리를 절약하고, 열거체를 사용하여 상태를 관리합니다.

#include <iostream>
using namespace std;

enum class DataType { INT, FLOAT, CHAR };

union Data {
    int intValue;
    float floatValue;
    char charValue;
};

struct DataContainer {
    DataType type;
    Data data;
};

void printData(const DataContainer& container) {
    switch (container.type) {
        case DataType::INT:
            cout << "Integer: " << container.data.intValue << endl;
            break;
        case DataType::FLOAT:
            cout << "Float: " << container.data.floatValue << endl;
            break;
        case DataType::CHAR:
            cout << "Char: " << container.data.charValue << endl;
            break;
    }
}

int main() {
    DataContainer container;
    
    container.type = DataType::INT;
    container.data.intValue = 42;
    printData(container);
    
    container.type = DataType::FLOAT;
    container.data.floatValue = 3.14;
    printData(container);
    
    container.type = DataType::CHAR;
    container.data.charValue = 'X';
    printData(container);
    
    return 0;
}



위 예제에서는 `DataContainer` 구조체를 사용하여 공용체와 열거체를 결합합니다. `DataContainer`는 `DataType` 열거체를 사용하여 현재 저장된 데이터의 타입을 나타내며, `Data` 공용체를 사용하여 실제 데이터를 저장합니다. `printData` 함수는 열거체 타입에 따라 공용체 데이터를 출력합니다. 이 구조는 다양한 타입의 데이터를 효율적으로 관리하면서도, 각 타입에 따라 적절한 처리를 할 수 있도록 돕습니다.

공용체와 열거체는 C++에서 각각의 특성과 장점을 가지고 있으며, 다양한 상황에서 유용하게 사용할 수 있습니다. 공용체는 메모리

 관리가 중요한 상황에서, 열거체는 코드의 가독성과 유지보수성을 높여야 하는 상황에서 특히 유용합니다.