[c] 왜 C Union이 필요한가요?

노동 조합은 언제 사용해야합니까? 왜 필요한가요?



답변

정수는 종종 이진 표현의 정수와 부동 소수점 사이를 변환하는 데 사용됩니다.

union
{
  int i;
  float f;
} u;

// Convert floating-point bits to integer:
u.f = 3.14159f;
printf("As integer: %08x\n", u.i);

이것은 C 표준에 따라 기술적으로 정의되지 않은 동작이지만 (가장 최근에 작성된 필드 만 읽어야 함) 거의 모든 컴파일러에서 잘 정의 된 방식으로 작동합니다.

또한 유니온은 C에 의사 다형성을 구현하는 데 사용됩니다. 구조체에 포함 된 객체의 유형을 나타내는 태그를 제공 한 다음 가능한 유형을 함께 결합하여 다음과 같습니다.

enum Type { INTS, FLOATS, DOUBLE };
struct S
{
  Type s_type;
  union
  {
    int s_ints[2];
    float s_floats[2];
    double s_double;
  };
};

void do_something(struct S *s)
{
  switch(s->s_type)
  {
    case INTS:  // do something with s->s_ints
      break;

    case FLOATS:  // do something with s->s_floats
      break;

    case DOUBLE:  // do something with s->s_double
      break;
  }
}

따라서 크기 struct S가 28이 아니라 12 바이트 만됩니다.


답변

유니온은 임베디드 프로그래밍 또는 하드웨어 / 메모리에 직접 액세스해야하는 상황에서 특히 유용합니다. 다음은 간단한 예입니다.

typedef union
{
    struct {
        unsigned char byte1;
        unsigned char byte2;
        unsigned char byte3;
        unsigned char byte4;
    } bytes;
    unsigned int dword;
} HW_Register;
HW_Register reg;

그런 다음 다음과 같이 reg에 액세스 할 수 있습니다.

reg.dword = 0x12345678;
reg.bytes.byte3 = 4;

엔디안 (바이트 순서) 및 프로세서 아키텍처는 물론 중요합니다.

또 다른 유용한 기능은 비트 수정 자입니다.

typedef union
{
    struct {
        unsigned char b1:1;
        unsigned char b2:1;
        unsigned char b3:1;
        unsigned char b4:1;
        unsigned char reserved:4;
    } bits;
    unsigned char byte;
} HW_RegisterB;
HW_RegisterB reg;

이 코드를 사용하면 레지스터 / 메모리 주소에서 단일 비트에 직접 액세스 할 수 있습니다.

x = reg.bits.b2;


답변

저수준 시스템 프로그래밍은 합리적인 예입니다.

IIRC, 유니온을 사용하여 하드웨어 레지스터를 구성 요소 비트로 분해했습니다. 따라서 구성 요소 비트에 8 비트 레지스터에 액세스 할 수 있습니다.

(정확한 구문은 잊었지만 …)이 구조를 통해 제어 레지스터를 control_byte 또는 개별 비트를 통해 액세스 할 수 있습니다. 주어진 엔디안에 대해 비트가 올바른 레지스터 비트에 매핑되도록하는 것이 중요합니다.

typedef union {
    unsigned char control_byte;
    struct {
        unsigned int nibble  : 4;
        unsigned int nmi     : 1;
        unsigned int enabled : 1;
        unsigned int fired   : 1;
        unsigned int control : 1;
    };
} ControlRegister;


답변

나는 객체 지향 상속을 대체하는 것으로 두 개의 라이브러리에서 그것을 보았습니다.

예 :

        Connection
     /       |       \
  Network   USB     VirtualConnection

Connection “클래스”가 위 중 하나가되도록하려면 다음과 같이 작성할 수 있습니다.

struct Connection
{
    int type;
    union
    {
        struct Network network;
        struct USB usb;
        struct Virtual virtual;
    }
};

libinfinity에서의 사용 예 : http://git.0x539.de/?p=infinote.git;a=blob;f=libinfinity/common/inf-session.c;h=3e887f0d63bd754c6b5ec232948027cbbf4d61fc;hb=HEAD#l74


답변

통합은 상호 배타적 인 데이터 멤버가 동일한 메모리를 공유 할 수 있도록합니다. 이것은 임베디드 시스템과 같이 메모리가 부족한 경우 매우 중요합니다.

다음 예에서

union {
   int a;
   int b;
   int c;
} myUnion;

이 공용체는 3 개의 개별 int 값이 아닌 단일 int의 공간을 차지합니다. 사용자의 값으로 설정하면 다음의 설정 값 B를 , 그것의 값을 덮어 쓰기 이들이 모두 동일한 메모리 위치를 공유하기 때문이다.


답변

많은 사용법. 그냥 grep union /usr/include/*또는 비슷한 디렉토리에 있습니다. 대부분의 경우에 union래핑되어 있고 struct구조체의 한 멤버는 공용체의 어느 요소에 액세스 할 수 있는지 알려줍니다. man elf실제 구현을위한 체크 아웃 을 예로들 수 있습니다.

이것이 기본 원칙입니다.

struct _mydata {
    int which_one;
    union _data {
            int a;
            float b;
            char c;
    } foo;
} bar;

switch (bar.which_one)
{
   case INTEGER  :  /* access bar.foo.a;*/ break;
   case FLOATING :  /* access bar.foo.b;*/ break;
   case CHARACTER:  /* access bar.foo.c;*/ break;
}


답변

다음은 내 자신의 코드베이스 (메모리 및 구문이 정확하지 않을 수 있음)의 통합 예입니다. 내가 작성한 인터프리터에 언어 요소를 저장하는 데 사용되었습니다. 예를 들어, 다음 코드는

set a to b times 7.

다음 언어 요소로 구성됩니다.

  • 상징 [세트]
  • 변수 [a]
  • 기호 [to]
  • 변수 [b]
  • 상징 [시간]
  • 상수 [7]
  • 상징[.]

언어 요소는 ‘ #define‘값 으로 정의되었습니다 .

#define ELEM_SYM_SET        0
#define ELEM_SYM_TO         1
#define ELEM_SYM_TIMES      2
#define ELEM_SYM_FULLSTOP   3
#define ELEM_VARIABLE     100
#define ELEM_CONSTANT     101

다음 구조를 사용하여 각 요소를 저장했습니다.

typedef struct {
    int typ;
    union {
        char *str;
        int   val;
    }
} tElem;

각 요소의 크기는 최대 합집합의 크기였습니다 (일반적인 값이지만 실제 크기는 구현에 따라 다름).

“set”요소를 작성하려면 다음을 사용하십시오.

tElem e;
e.typ = ELEM_SYM_SET;

“variable [b]”요소를 작성하려면 다음을 사용하십시오.

tElem e;
e.typ = ELEM_VARIABLE;
e.str = strdup ("b");   // make sure you free this later

“constant [7]”요소를 작성하려면 다음을 사용하십시오.

tElem e;
e.typ = ELEM_CONSTANT;
e.val = 7;

float ( float flt) 또는 rationals ( struct ratnl {int num; int denom;}) 및 기타 유형 을 포함하도록 쉽게 확장 할 수 있습니다 .

기본 전제는 점이다 strval그 구조는 메모리 위치에 기초하고, 여기서 도시 된 동일한 메모리 블록에 다른 뷰를 얻는 방법 그래서 그들은 오버랩 실제로 메모리에 인접하지 않은 0x1010및 정수 및 포인터 모두이다 4 바이트:

       +-----------+
0x1010 |           |
0x1011 |    typ    |
0x1012 |           |
0x1013 |           |
       +-----+-----+
0x1014 |     |     |
0x1015 | str | val |
0x1016 |     |     |
0x1017 |     |     |
       +-----+-----+

구조에 있다면 다음과 같습니다.

       +-------+
0x1010 |       |
0x1011 |  typ  |
0x1012 |       |
0x1013 |       |
       +-------+
0x1014 |       |
0x1015 |  str  |
0x1016 |       |
0x1017 |       |
       +-------+
0x1018 |       |
0x1019 |  val  |
0x101A |       |
0x101B |       |
       +-------+