5.1.4. 구조체, 공용체, 열거 및 비트 필드

이 단원에서는 구조화된 데이터 유형 union, enum 및 struct의 구현에 대해 설명합니다. 또한 구조체 패딩과 비트 필드 구현에 대해서도 설명합니다.

자세한 내용은 익명 클래스, 구조체 및 공용체를 참조하십시오.

공용체

union의 구성원을 다른 유형의 구성원을 통해 액세스하면 결과 값은 원래 유형의 표현으로부터 예상할 수 있습니다. 오류는 발생하지 않습니다.

열거

개체 유형 enumenum의 범위가 포함된 최소 정수 유형에서 구현됩니다. 저장 유형 enumenum의 열거자 범위에 따라 다음 중 첫 번째입니다.

  • --enum_is_int를 사용하지 않을 경우 unsigned char

  • --enum_is_int를 사용하지 않을 경우 signed char

  • --enum_is_int를 사용하지 않을 경우 unsigned short

  • --enum_is_int를 사용하지 않을 경우 signed short

  • signed int

  • --strict가 있는 C를 제외하고 unsigned int

  • --strict가 있는 C를 제외하고 signed long long

  • --strict가 있는 C를 제외하고 unsigned long long

이런 방식으로 enum를 구현하면 데이터 크기를 줄일 수 있습니다. 명령 행 옵션 --enum_is_int는 기본 유형 enum을 최소한 int만큼 넓게 만들어 줍니다.

자세한 내용은 ARM 아키텍처용 프로시저 호출 표준 사양에서 C 언어 매핑에 대한 설명을 참조하십시오.

Note

--enum_is_int 옵션을 사용하거나 사용하지 않고 컴파일되었으며 인터페이스 또는 데이터 구조를 공유하는 변환 단위를 혼합할 때는 주의해야 합니다.

범위를 벗어난 값의 처리

엄격한 C에서는 열거자 값을 int로 나타낼 수 있어야 합니다. 예를 들어 열거자 값은 -2147483648 ~ +2147483647의 범위에 있어야 합니다. 이전 릴리스의 RVCT에서는 --strict 옵션을 지정하지 않은 경우 값이 범위를 벗어나면 해당 값이 int로 캐스트되고 경고는 표시되지 않았습니다.

RVCT v2.2 이상에서는 범위를 벗어난 열거자 값에 대해 다음과 같은 경고가 발생합니다.

#66: enumeration value is out of "int" range

이런 값은 C++에서와 동일한 방식으로 처리됩니다. 즉, unsigned int, long long 또는 unsigned long long으로 처리됩니다.

범위를 벗어난 값에 대한 경고가 보고되도록 하려면 다음 명령을 사용하여 경고를 오류로 변경하십시오.

armcc --diag_error=66 ...

구조체

다음 사항은 아래 항목에 적용됩니다.

  • 모든 C 구조체

  • 가상 함수나 기본 클래스를 사용하지 않는 모든 C++ 구조체와 클래스

구조체 정렬

패킹되지 않는 구조체의 정렬은 해당 필드에 필요한 최대 정렬입니다.

필드 정렬

구조체는 최하위 주소에 첫 번째로 명명된 구성요소에 의해 배열됩니다. 필드는 다음과 같이 정렬됩니다.

  • char 유형의 필드는 사용 가능한 다음 바이트에 정렬됩니다.

  • short 유형의 필드는 짝수 주소의 다음 바이트에 정렬됩니다.

  • RVCT v2.0 이상에서는 doublelong long 데이터 유형이 8바이트 단위로 정렬됩니다. 따라서 ARMv5TE 이상에서 LDRDSTRD 명령어를 효율적으로 사용할 수 있습니다.

  • 비트 필드 정렬은 비트 필드가 선언되는 방식에 따라 달라집니다. 자세한 내용은 패킹된 구조체의 비트 필드를 참조하십시오.

  • 다른 모든 유형은 워드 단위로 정렬됩니다.

구조체에는 필드가 정확히 정렬되고 구조체 자체가 정확히 정렬되도록 패딩이 포함될 수 있습니다. Figure 5.1에서는 패킹되지 않은 기존 구조체의 한 예를 보여 줍니다. 바이트 1, 2 및 3은 정확한 필드 정렬을 보장하기 위해 패딩됩니다. 바이트 11 및 12는 정확한 구조체 정렬을 보장하기 위해 패딩됩니다. sizeof() 함수는 패딩을 포함하여 구조체의 크기를 반환합니다.

Figure 5.1. 패킹되지 않는 기존 구조체의 예

컴파일러는 구조체의 정의 방식에 따라 다음 방법 중 하나로 구조체를 패딩합니다.

  • static 또는 extern으로 정의된 구조체는 0으로 패딩됩니다.

  • malloc() 또는 auto를 사용하여 정의된 구조체처럼 스택이나 힙의 구조체는 해당 메모리 위치에 이전에 저장된 것을 사용하여 패딩됩니다. 이런 방식으로 정의된 패딩된 구조를 비교하는 데 memcmp()를 사용할 수 없습니다(Figure 5.1 참조).

컴파일러가 struct에 패딩을 삽입할 때 생성된 메시지를 보려면 --remarks 옵션을 사용하십시오.

빈 이니셜라이저가 있는 구조는 C++에서 허용됩니다.

struct
{
    int x;
} X = { };

그러나 -cpp--c90 옵션을 사용하여 C 또는 C++를 컴파일하면 오류가 생성됩니다.

패킹된 구조체

구조체 및 구조체 내의 필드의 정렬이 항상 1인 경우 패킹된 구조체는 하나입니다.

패킹된 구조체는 __packed 한정자를 사용하여 정의됩니다. 기본 구조체 패킹을 변경하는 명령 행 옵션은 없습니다.

비트 필드

패킹되지 않는 구조체에서 ARM 컴파일러는 컨테이너에 비트 필드를 할당합니다. 컨테이너는 선언된 유형을 가진 정확히 정렬된 개체입니다.

비트 필드는 구성에 따라 첫 번째로 지정된 필드가 워드의 최하위 주소를 가진 비트를 차지하도록 할당됩니다.

리틀엔디안

최하위 주소를 가진다는 것은 중요도가 가장 낮다는 것을 의미합니다.

빅엔디안

최하위 주소를 가진다는 것은 중요도가 가장 높다는 것을 의미합니다.

비트 필드 컨테이너는 어떤 정수 유형도 될 수 있습니다.

Note

엄격한 1990 ISO 표준 C에서 비트 필드에 허용된 유형은 int, signed intunsigned int뿐입니다. int 계열이 아닌 비트 필드의 경우 컴파일러에 오류가 표시됩니다.

signed 또는 unsigned 한정자 없이 선언되는 일반 비트 필드는 unsigned로 처리됩니다. 예를 들어 int x:10은 10비트의 부호 없는 정수를 할당합니다.

비트 필드는 충분한 수의 미할당 비트를 가진 올바른 유형의 첫 번째 컨테이너에 할당됩니다. 예를 들면 다음과 같습니다.

struct X
{
    int x:10;
    int y:20;
};

첫 번째 선언은 정수 컨테이너를 생성하고 10비트를 x에 할당합니다. 두 번째 선언에서 컴파일러는 충분한 수의 미할당 비트가 있는 기존의 정수 컨테이너를 찾아 x와 동일한 컨테이너에 y를 할당합니다.

비트 필드는 완전히 해당 컨테이너에 포함됩니다. 컨테이너에 들어가지 않는 비트 필드는 동일한 유형을 가진 다음 컨테이너에 배치됩니다. 예를 들어 구조체에 대해 추가 비트 필드가 선언될 경우 z의 선언은 컨테이너를 오버플로합니다.

struct X
{
    int x:10;
    int y:20;
    int z:5;
};

컴파일러는 첫 번째 컨테이너의 나머지 2비트를 패딩하고 z에 대한 새 정수 컨테이너를 할당합니다.

비트 필드 컨테이너는 서로 중복될 수 있습니다. 예를 들면 다음과 같습니다.

struct X
{
    int x:10;
    char y:2;
};

첫 번째 선언은 정수 컨테이너를 생성하고 10비트를 x에 할당합니다. 이 10비트는 정수 컨테이너의 첫 번째 바이트와 두 번째 바이트의 2비트를 차지합니다. 두 번째 선언에서 컴파일러는 char 유형의 컨테이너를 확인합니다. 적합한 컨테이너가 없으므로 컴파일러는 올바르게 정렬된 새 char 컨테이너를 할당합니다.

char의 기본 정렬이 1이므로 컴파일러는 비트 필드를 모두 포함하기 위해 충분한 수의 미할당 비트가 있는 첫 번째 바이트를 검색합니다. 이 예제 구조체에서 int 컨테이너의 두 번째 바이트의 2비트는 x에 할당되고 6비트는 할당되지 않습니다. 컴파일러는 이전 int 컨테이너의 두 번째 바이트에서 시작되는 char 컨테이너를 할당하고, x에 할당되는 처음 2비트를 건너뛰고, 2비트를 y에 할당합니다.

ychar y:8로 선언될 경우 비트 필드가 컨테이너를 오버플로할 수 없기 때문에 컴파일러는 두 번째 바이트를 패딩하고 새 char 컨테이너를 세 번째 바이트에 할당합니다. Figure 5.2에서는 다음 예제 구조체에 대한 비트 필드 할당을 보여 줍니다.

struct X
{
    int x:10;
    char y:8;
};

Figure 5.2. 비트 필드 할당 1

Note

동일한 기본 규칙이 다른 컨테이너 유형을 가진 비트 필드 선언에 적용됩니다. 예를 들어 int 비트 필드를 예제 구조에 추가하면 결과는 다음과 같습니다.

struct X
{
    int x:10;
    char y:8;
    int z:5;
}

컴파일러는 int x:10 컨테이너와 동일한 위치에서 시작되는 int 컨테이너를 할당하고, 바이트 단위 정렬 char 및 5비트 비트 필드를 할당합니다(Figure 5.3 참조).

Figure 5.3. 비트 필드 할당 2

명명되지 않은 0 크기의 비트 필드를 선언함으로써 비트 필드 컨테이너를 명시적으로 패딩할 수 있습니다. 0 크기의 비트 필드는 컨테이너가 비어 있지 않을 경우 컨테이너를 끝까지 채웁니다. 다음 비트 필드 선언은 비어 있는 새 컨테이너를 시작합니다.

패킹된 구조체의 비트 필드

패킹된 구조체의 비트 필드는 1의 정렬을 갖습니다. 따라서 패킹된 구조체의 비트 필드에 대한 최대 비트 패딩은 7비트입니다. 패킹되지 않은 구조체의 경우 최대 패딩은 8*sizeof(container-type)-1 bits입니다.

Copyright © 2007 ARM Limited. All rights reserved.ARM DUI 0348AK
Non-Confidential