`UNION`과 `MAP`

UNIONMAP

구식 프로그램을 뒤지다 보면 STRUCTURE 선언 안에 UNIONMAP이 등장하는 코드를 만날 때가 있어요. 예전 벤더 확장으로 널리 쓰였던 문법인데, 메모리를 겹쳐 쓰는 공용체(union)를 Fortran에서 흉내 낸 거예요. C의 공용체와 어떻게 비슷하고 다른지 예제와 함께 살펴볼게요.

출처: UNION and MAP

본문

UNION은 옛날 벤더 확장으로, 비표준 확장인 STRUCTURERECORD와 함께 자주 쓰였어요. UNIONMAP 사용은 -fdec-structure 옵션으로 자동으로 활성화돼요.

UNION 선언은 구조체 안에 나타나요. 각 UNION에는 여러 개의 MAP 블록이 들어가죠. 같은 공용체 안에 있는 MAP들은 서로 스토리지를 공유하고, 공용체의 크기는 그 안에서 가장 큰 MAP의 크기와 같아요. 이건 C의 공용체와 같은 동작이에요. 큰 차이는 하나인데, 컴포넌트 참조가 그 컴포넌트가 어느 UNION이나 MAP에 속하는지 명시하지 않는다는 점이에요. 컴파일러가 알아서 판단하게 되죠.

작은 예제를 볼게요.

 structure /myunion/
   union
     map
       character(2) w0, w1, w2
     end map
     map
       character(6) long
     end map
   end union
 end structure
 record /myunion/ rec
 ! After this assignment...
 rec.long = 'hello!'
 ! The following is true:
 ! rec.w0 === 'he'
 ! rec.w1 === 'll'
 ! rec.w2 === 'o!'

이 예에서 두 MAP은 메모리를 공유하고, 공용체의 크기는 결국 6바이트가 돼요.

 0   1   2   3   4   5   6   Byte offset
 -------------------------------
 |   |   |   |   |   |   |
 -------------------------------
  ^   W0   ^   W1   ^   W2   ^
  \-------/ \-------/ \-------/
  ^        LONG          ^
  \----------------------/

이번에는 Intel x86_64 레지스터의 배치를 그대로 흉내 낸 예제예요.

 structure /reg/
   union
     ! U0
     ! rax
     map
       character(16) rx
     end map
     map
       character(8) rh
       ! rah
       union
         ! U1
         map
           character(8) rl
           ! ral
         end map
         map
           character(8) ex
           ! eax
         end map
         map
           character(4) eh
           ! eah
           union
             ! U2
             map
               character(4) el
               ! eal
             end map
             map
               character(4) x
               ! ax
             end map
             map
               character(2) h
               ! ah
               character(2) l
               ! al
             end map
           end union
         end map
       end union
     end map
   end union
 end structure
 record /reg/ a
 ! After this assignment...
 a.rx = 'AAAAAAAA.BBB.C.D'
 ! The following is true:
 a.rx === 'AAAAAAAA.BBB.C.D'
 a.rh === 'AAAAAAAA'
 a.rl === '.BBB.C.D'
 a.ex === '.BBB.C.D'
 a.eh === '.BBB'
 a.el === '.C.D'
 a.x === '.C.D'
 a.h === '.C'
 a.l === '.D'

이렇게 겹쳐 놓은 메모리 영역을 통해, 하나의 레지스터를 16바이트 전체로 읽을 수도, 8바이트 상위·하위로 나눠 읽을 수도 있게 돼요. C의 공용체와 같은 원리지만, 어느 MAP을 쓸지 명시하지 않아도 된다는 점이 Fortran 확장의 특징이에요.

더 알아보기

  • UNION/MAP-fdec-structure 옵션이 켜지면 자동으로 활성화되는 DEC 호환 확장이에요.
  • 함께 쓰이는 STRUCTURERECORD 선언에 대한 자세한 설명은 GNU Fortran 매뉴얼을 참고하면 좋아요.
  • 이런 비표준 확장은 새 프로젝트보다는 옛 소스 호환을 위해 쓰이니, 가능하면 표준 문법으로 마이그레이션하는 편이 좋아요.