programing

C-store에서의 조합에 대한 질문 - 하나의 유형으로, 다른 유형으로 읽음 - 구현이 정의되어 있습니까?

starjava 2023. 10. 24. 20:04
반응형

C-store에서의 조합에 대한 질문 - 하나의 유형으로, 다른 유형으로 읽음 - 구현이 정의되어 있습니까?

K&R에서 C의 union에 대해 읽고 있었는데, 제가 알기로는 union의 단일 변수는 여러 유형 중 어느 하나를 보유할 수 있고 어떤 것이 한 유형으로 저장되고 다른 유형으로 추출되면 순수하게 구현이 정의되는 것으로 알고 있습니다.

이제 다음 코드 스니펫을 확인해 주시기 바랍니다.

#include<stdio.h>

int main(void)
{
  union a
  {
     int i;
     char ch[2];
  };

  union a u;
  u.ch[0] = 3;
  u.ch[1] = 2;

  printf("%d %d %d\n", u.ch[0], u.ch[1], u.i);

  return 0;
}

출력:

3 2 515

여기에 값을 할당합니다.u.ch하지만 둘 다에서 검색하는 것.u.ch그리고.u.i은 실행이 구현이 정의되어 있습니까?아니면 내가 정말 바보같은 짓을 하는 걸까요?

대부분의 다른 사람들에게는 매우 초보적인 것으로 보일 수도 있다는 것을 알고 있지만 그 결과물에 대한 이유를 알 수 없습니다.

감사해요.

이는 정의되지 않은 동작입니다.u.i그리고.u.ch동일한 메모리 주소에 위치합니다.따라서 하나에 쓰고 다른 하나를 읽는 결과는 컴파일러, 플랫폼, 아키텍처, 그리고 때로는 컴파일러의 최적화 수준에 따라 달라집니다.따라서 다음에 대한 출력.u.i항상 그렇지는 않을 것입니다515.

예를들면gcc내 기계에서 두가지 다른 답변을 만들어냅니다.-O0그리고.-O2.

  1. 제 기계는 32비트 리틀 엔디언 아키텍처를 가지고 있기 때문입니다.-O0결국 2와 3으로 초기화된 최하위 바이트가 2개가 되고, 최상위 바이트 2개는 초기화되지 않습니다.그래서 노조의 기억은 다음과 같습니다.{3, 2, garbage, garbage}

    따라서 나는 다음과 비슷한 출력을 얻습니다.3 2 -1216937469.

  2. 와 함께-O2, 결과는 알 수 있습니다.3 2 515당신이 하는 것처럼 조합의 기억을 만드는 거죠{3, 2, 0, 0}. 무슨 일이 일어나냐 하면gcc에 통화를 최적화합니다.printf실제 값을 사용하면 어셈블리 출력이 다음과 동등하게 보입니다.

    #include <stdio.h>
    int main() {
        printf("%d %d %d\n", 3, 2, 515);
        return 0;
    }
    

    515 값은 이 질문에 대한 다른 답변에서 설명한 대로 구할 수 있습니다.본질적으로 그것은 다음과 같은 것을 의미합니다.gcc0을 초기화되지 않은 조합의 임의 값으로 선택한 호출을 최적화했습니다.

한 조합원에게 글을 쓰고 다른 조합원으로부터 글을 읽는 것은 보통 큰 의미가 없지만, 때로는 엄격한 별칭으로 컴파일된 프로그램에 유용할 수도 있습니다.

이 질문에 대한 답은 시대에 따라 언어의 명세가 바뀌었기 때문에 역사적 맥락에 따라 달라집니다.그리고 이 문제는 그 변화에 영향을 받는 문제입니다.

K&R을 읽고 있다고 하셨잖아요.그 책의 최신 판(현재)에는 C 언어의 첫 번째 표준화된 버전인 C89/90이 설명되어 있습니다.C 언어의 그 버전에서는 한 조합원을 쓰고 다른 조합원을 읽는 것은 정의되지 않은 행동입니다.구현이 정의된 것이 아니라(다른 것임), 정의되지 않은 동작입니다.이 경우 언어 표준의 관련 부분은 6.5/7입니다.

이제, C (Technical Corrigendum 3이 적용된 언어 사양의 C99 버전)의 진화의 어느 시점에서, 갑자기 유니언을 타이프닝에 사용하는 것이 합법화되었습니다. 즉, 유니언의 한 구성원을 쓰고 다른 구성원을 읽는 것입니다.

이를 시도하면 여전히 정의되지 않은 동작이 발생할 수 있습니다.읽은 값이 읽지 않은 유형에 대해 유효하지 않은 경우("트랩 표현"이라고 함), 동작은 여전히 정의되지 않습니다.그렇지 않으면 판독한 값이 구현으로 정의됩니다.

당신의 특정한 예는 상대적으로 다음으로부터 유형 펀닝을 하기에 안전합니다.int.char[2]배열. 어떤 물체의 내용을 문자 배열로 재해석하는 것은 C 언어로 항상 합법적입니다(다시 6.5/7).

그러나 그 반대는 사실이 아닙니다.데이터를 에 쓰는 중char[2]당신의 조합원을 배열하고 그 다음에 그것을 읽습니다.int잠재적으로 트랩 표현을 생성하여 정의되지 않은 동작을 초래할 수 있습니다.잠재적인 위험은 당신의 차열이 전체를 덮을 수 있는 충분한 길이를 가지고 있더라도 존재합니다.int.

하지만 당신의 구체적인 경우에는, 만약int때마침 보다 더 큰char[2],int읽기 시작하면 배열 끝 너머의 초기화되지 않은 영역이 포함되며, 이 영역은 다시 정의되지 않은 동작으로 이어집니다.

출력 뒤에 있는 이유는 컴퓨터에 정수가 리틀 엔디안 형식으로 저장되기 때문입니다. 최하위 바이트가 먼저 저장되기 때문입니다.따라서 바이트 시퀀스 [3,2,0,0]는 정수 3+2*256=515를 나타냅니다.

이 결과는 구체적인 구현과 플랫폼에 따라 달라집니다.

이러한 코드의 출력은 당신의 플랫폼과 C 컴파일러 구현에 따라 달라질 것입니다.출력을 보니 이 코드를 작은 엔디언 시스템(아마도 x86)에서 실행하고 있는 것 같습니다.만약 당신이 i에 515를 넣고 디버거에서 본다면, 당신은 가장 낮은 차수의 바이트가 3이고 메모리에서 다음 바이트가 2인 것을 알 수 있을 것이고, 당신이 ch에 넣은 것과 정확히 매핑되는 것을 알 수 있을 것입니다.

빅 엔디언 시스템에서 이 작업을 수행했다면 770(16비트 int 가정) 또는 50462720(32비트 int 가정)을 얻을 수 있었을 것입니다.

구현에 따라 다르며 다른 플랫폼/컴파일러에 따라 결과가 달라질 수 있습니다. 하지만 이런 현상이 일어나는 것 같습니다.

515의 이진법은

1000000011

0을 추가하여 2바이트(16비트 int로 가정):

0000001000000011

두 바이트는 다음과 같습니다.

00000010 and 00000011

어느 것이2그리고.3

누군가가 그것들이 왜 뒤바뀌었는지 설명해주기를 바랍니다 - 제 추측으로는 문자들이 거꾸로 되지는 않지만 그 의도는 거의 엔디안인 것 같습니다.

유니언에 할당된 메모리의 양은 가장 큰 멤버를 저장하는 데 필요한 메모리와 같습니다.이 경우 길이 2의 int 및 char 배열이 있습니다.int를 16비트, char를 8비트라고 가정하면 둘 다 같은 공간이 필요하므로 유니언에 2바이트가 할당됩니다.

char 배열에 3개(000011)와 2개(000010)를 할당하면 결합 상태는0000001100000010. 이 조합의 int를 읽으면 전체가 정수로 변환됩니다.LSB가 가장 낮은 주소로 저장되는 리틀 엔디언 표현을 가정할 때, 조합의 내부는0000001000000011515에 대한 이진법입니다.

참고: 이는 int가 32bit인 경우에도 성립합니다. - Amnon의 답변 확인

32비트 시스템의 경우 int는 4바이트이지만 초기화는 2바이트에 불과합니다.초기화되지 않은 데이터에 액세스하는 것은 정의되지 않은 동작입니다.

16비트 int를 사용하는 시스템을 사용한다고 가정할 때, 사용자가 수행하는 작업은 여전히 구현이 정의되어 있습니다.시스템이 작은 엔디안인 경우 u.ch [0]은 최하위 바이트인 u.i와 일치하며 u.ch1은 최상위 바이트가 됩니다.큰 엔디언 시스템에서는 반대입니다.또한 C 표준은 2의 보어가 가장 일반적이지만 구현이 2의 보어를 사용하여 부호가 있는 정수 값을 나타내도록 강제하지 않습니다.분명히 정수의 크기도 구현으로 정의됩니다.

힌트: 16진수 값을 사용하면 무슨 일이 일어나고 있는지 쉽게 알 수 있습니다.약간의 엔디언 시스템에서, hex의 결과는 0x0203이 될 것입니다.

언급URL : https://stackoverflow.com/questions/1812348/a-question-about-union-in-c-store-as-one-type-and-read-as-another-is-it-impl

반응형