programing

C/C++ 단위의 결합 크기

yoursource 2022. 7. 17. 11:01
반응형

C/C++ 단위의 결합 크기

C/C++의 유니언 사이즈는 어떻게 됩니까?그 안에 있는 가장 큰 데이터 타입의 크기인가요?만약 그렇다면, 유니언의 작은 데이터 타입 중 하나가 활성화 되어 있다면, 컴파일러는 어떻게 스택포인터를 이동하는지를 계산합니까?

A union항상 가장 큰 멤버만큼 많은 공간을 차지합니다.현재 사용 중인 것은 중요하지 않습니다.

union {
  short x;
  int y;
  long long z;
}

union 1은 필요하다long long장용입입니니다

사이드 노트:Stefano가 지적한 바와 같이 실제 공간은 임의의 유형이다.union,struct,class)는 컴파일러에 의한 정렬 등 기타 문제에 따라 달라집니다.나는 단지 조합이 가장 큰 항목을 고려한다는 것을 말하고 싶었기 때문에 단순하게 이것을 검토한 것이 아니다.실제 크기는 정렬에 따라 다르다는 것을 알아야 합니다.

이 표준은 C++ 표준의 섹션 9.5 또는 C99 표준의 섹션 6.5.2.3 단락 5(또는 C11 표준의 단락 6 또는 C18 표준의 섹션 6.7.2.1 단락 16)의 모든 질문에 답변한다.

유니언에서는 데이터 멤버 중 적어도 하나는 언제든지 활성화 할 수 있다.즉, 데이터 멤버 중 최대 하나는 언제든지 유니언에 격납할 수 있다.[주: 유니언 사용을 간소화하기 위해 다음과 같은 특별한 보증이 있습니다.POD 결합에 공통의 초기 시퀀스(9.2)를 공유하는 여러 개의 POD 구조가 포함되어 있고 이 POD 결합 유형의 개체가 POD 구조 중 하나를 포함하는 경우 POD 구조 구성원의 공통 초기 시퀀스(9.2 참조)를 검사하는 것이 허용된다. 결합의 크기는 결합 구성원의 가장 큰 데이터를 포함하기에 충분하다.각 데이터 부재는 구조체의 유일한 부재인 것처럼 할당됩니다.

즉, 각 구성원은 동일한 메모리 영역을 공유합니다.활동 중인 멤버는 많아야 한 명인데 어떤 멤버를 찾을 수 없습니다.현재 활동 중인 멤버에 대한 정보를 다른 곳에 직접 저장해야 합니다.이러한 플래그를 유니언과 함께 저장하면(예를 들어 타입 플래그로 정수를 가진 구조, 데이터 스토어로 유니언을 갖는 구조), 이른바 "차별된 유니언"이 됩니다. 즉, 유니언에서 현재 어떤 타입이 액티브한 유니언인지 알고 있는 유니언입니다.

토큰을 수 하는 정보가 .line공통의 초기 시퀀스가 무엇인지를 나타내는 각 구조체:

struct tokeni {
    int token; /* type tag */
    union {
        struct { int line; } noVal;
        struct { int line; int val; } intVal;
        struct { int line; struct string val; } stringVal;
    } data;
};

표준을 할 수 .line각 멤버들의 공통적인 초기 순서이기 때문입니다.

현재 값이 저장되어 있는 멤버를 무시하고 모든 멤버에 액세스할 수 있는 컴파일러 확장이 있습니다.이를 통해 멤버별로 다른 유형의 저장된 비트를 효율적으로 재해석할 수 있습니다.예를 들어, 플로트 변수를 2개의 부호 없는 쇼트로 분할하려면 다음을 사용할 수 있습니다.

union float_cast { unsigned short s[2]; float f; };

그것은 낮은 수준의 코드를 작성할 때 매우 편리합니다.컴파일러가 그 확장을 지원하지 않지만 그래도 할 경우 결과가 정의되지 않은 코드를 작성합니다.따라서 이 방법을 사용하는 경우 컴파일러가 이 기능을 지원하는지 확인하십시오.

컴파일러와 옵션에 따라 다릅니다.

int main() {
  union {
    char all[13];
    int foo;
  } record;

printf("%d\n",sizeof(record.all));
printf("%d\n",sizeof(record.foo));
printf("%d\n",sizeof(record));

}

출력은 다음과 같습니다.

13 4 16

제 기억이 맞다면 컴파일러가 할당된 공간에 넣는 정렬에 따라 다릅니다.따라서 특별한 옵션을 사용하지 않는 한 컴파일러는 당신의 유니언 공간에 패딩을 넣을 것입니다.

edit: gcc에서는 pragma 디렉티브를 사용해야 합니다.

int main() {
#pragma pack(push, 1)
      union {
           char all[13];
           int foo;
      } record;
#pragma pack(pop)

      printf("%d\n",sizeof(record.all));
      printf("%d\n",sizeof(record.foo));
      printf("%d\n",sizeof(record));

}

이 출력물

13 4 13

분해에서도 확인할 수 있습니다(명확하게 하기 위해 일부 인쇄물을 제거했습니다).

  0x00001fd2 <main+0>:    push   %ebp             |  0x00001fd2 <main+0>:    push   %ebp
  0x00001fd3 <main+1>:    mov    %esp,%ebp        |  0x00001fd3 <main+1>:    mov    %esp,%ebp
  0x00001fd5 <main+3>:    push   %ebx             |  0x00001fd5 <main+3>:    push   %ebx
  0x00001fd6 <main+4>:    sub    $0x24,%esp       |  0x00001fd6 <main+4>:    sub    $0x24,%esp
  0x00001fd9 <main+7>:    call   0x1fde <main+12> |  0x00001fd9 <main+7>:    call   0x1fde <main+12>
  0x00001fde <main+12>:   pop    %ebx             |  0x00001fde <main+12>:   pop    %ebx
  0x00001fdf <main+13>:   movl   $0xd,0x4(%esp)   |  0x00001fdf <main+13>:   movl   $0x10,0x4(%esp)                                         
  0x00001fe7 <main+21>:   lea    0x1d(%ebx),%eax  |  0x00001fe7 <main+21>:   lea    0x1d(%ebx),%eax
  0x00001fed <main+27>:   mov    %eax,(%esp)      |  0x00001fed <main+27>:   mov    %eax,(%esp)
  0x00001ff0 <main+30>:   call  0x3005 <printf>   |  0x00001ff0 <main+30>:   call   0x3005 <printf>
  0x00001ff5 <main+35>:   add    $0x24,%esp       |  0x00001ff5 <main+35>:   add    $0x24,%esp
  0x00001ff8 <main+38>:   pop    %ebx             |  0x00001ff8 <main+38>:   pop    %ebx
  0x00001ff9 <main+39>:   leave                   |  0x00001ff9 <main+39>:   leave
  0x00001ffa <main+40>:   ret                     |  0x00001ffa <main+40>:   ret    

여기서 유일한 차이는 main+13으로 컴파일러가 0x10이 아닌 스택0xd에 할당됩니다.

결합에 대한 활성 데이터 유형의 개념은 없습니다.당신은 조합의 어떤 회원이라도 읽고 쓸 수 있다: 당신이 얻은 것을 해석하는 것은 당신에게 달려 있다.

따라서 유니언의 크기는 항상 가장 큰 데이터 유형의 크기입니다.

C/C++의 유니언 사이즈는 어떻게 됩니까?그 안에 있는 가장 큰 데이터 타입의 크기인가요?

, 조합의 규모는 가장 큰 조합원의 크기입니다.

예:

#include<stdio.h>

union un
{
    char c;
    int i;
    float f;
    double d;
};

int main()
{
    union un u1;
    printf("sizeof union u1 : %ld\n",sizeof(u1));
    return 0;
}

출력:

sizeof union u1 : 8
sizeof double d : 8

서 큰 는 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.double 둘다가 있다.8그...로서sizeof, 「아니다」 「아니다」 「아니다」8.

유니언의 작은 데이터 유형 중 하나가 활성화 되어 있을 때 컴파일러는 스택 포인터를 어떻게 움직이는지 계산합니까?

컴파일러가 내부적으로 처리합니다.유니언의 데이터 멤버 중 하나에 액세스한다고 가정하면 각 데이터 멤버가 동일한 메모리를 공유하기 때문에 유니언의 단일 데이터 멤버에 액세스할 수 있기 때문에 다른 데이터 멤버에 액세스할 수 없습니다.유니언을 사용하면 귀중한 공간을 많이 절약할 수 있습니다.

유니언은 유니언 내에서 가장 큰 데이터 유형의 컨테이너로 간주해야 하며, 이는 캐스팅에 대한 바로 가기와 결합해야 합니다.작은 멤버 중 하나를 사용하면 사용되지 않은 공간은 그대로 남아 있지만 사용되지 않은 상태로 남아 있을 뿐입니다.

이것은 Unix의 ioctl() 콜과 조합하여 사용되는 경우가 많습니다.모든 ioctl() 콜은 동일한 구조를 통과합니다.이 구조에는 가능한 모든 응답의 조합이 포함됩니다.예를 들어, 이 예는 /usr/include/linux/if.h에서 가져온 것으로, 이 구조는 ioctl()에서 이더넷인터페이스의 상태를 설정/쿼리하기 위해 사용됩니다.요청 파라미터는 유니언에서 실제로 사용되는 부분을 정의합니다.

struct ifreq 
{
#define IFHWADDRLEN 6
    union
    {
        char    ifrn_name[IFNAMSIZ];        /* if name, e.g. "en0" */
    } ifr_ifrn;

    union {
        struct  sockaddr ifru_addr;
        struct  sockaddr ifru_dstaddr;
        struct  sockaddr ifru_broadaddr;
        struct  sockaddr ifru_netmask;
        struct  sockaddr ifru_hwaddr;
        short   ifru_flags;
        int ifru_ivalue;
        int ifru_mtu;
        struct  ifmap ifru_map;
        char    ifru_slave[IFNAMSIZ];   /* Just fits the size */
        char    ifru_newname[IFNAMSIZ];
        void *  ifru_data;
        struct  if_settings ifru_settings;
    } ifr_ifru;
};

크기는 적어도 가장 큰 구성 유형의 크기여야 합니다.'액티브' 타입의 개념은 없습니다.

  1. 가장 큰 멤버의 크기입니다.

  2. 노조 내부에서는 어느 쪽이 '적극적' 구성원인지를 나타내는 깃발이 있는 것이 일반적인 이유다.

예:

struct ONE_OF_MANY {
    enum FLAG { FLAG_SHORT, FLAG_INT, FLAG_LONG_LONG } flag;
    union { short x; int y; long long z; };
};

언급URL : https://stackoverflow.com/questions/740577/sizeof-a-union-in-c-c

반응형