필드 심볼(Field Symbol)이란?

: abap에서 메모리의 특정위치를 가리키는 이름 없는 변수

- 변수에 직접 접근 x

- 참조 형태로 데이터에 접근

- 필드심볼은 ABAP 프로그램 내에서 변수에 동적인 접근이 가능하게 함

- 필드심볼은 자기 자신을 위한 메모리 공간을 점유하지 않는다.

- 필드심볼의 데이터 이름과 속성은 실행 시점에 결정된다.

- 필드 심볼은 모든 데이터 오브젝트에 지정될 수 있다.

- 필드심볼이 할당되면 데이터 오브젝트와 필드심볼간에는 차이가 없다.

- Move와 같은 Abap명령어도 같이 사용할 수 있다.

- 필드 심볼을 명시하여 선언하거나 타입 없이 생성할 수 있다. 타입이 명시되지 않으면 할당되는 필드(오브젝트)의 타입을 그대로 상속받는다.

 

- gv_var의 변수의 값은 'A'였지만, write결과 'B'가 된것을 확인할 수 있다.

- 이는 gv_var 변수를 필드 심볼에 Assign했고, 필드 심볼의 값을 'B'로 변경했기 때문이다.

 

Generic TYPE Field Symbol

- 필드심볼을 선언할 때 타입을 지정하지 않고 할당되는 데이터 오브젝트 유형에 따라 기술적인 속성을 상속받게 된다. 

- Field-symbols <f2> type any tablr을 사용하려면 assign 구문에서 할당할 오브젝트가 인터널 테이블 타입으로 선언되어야 한다. 

- 이렇게 선언된 필드 심볼은 그 자체가 인터널 테이블이 되어 READ와 같은 구문을 사용할 수 있다.

- TABLE키워드를 삭제하고 TYPE ANY만 사용하면 LINE 타입의 구조체로 활용할 수 있다.

 

gv_var is B, fs is B. 이다.

 

- TYPE ANY는 정확한 데이터 타입을 모를 때 쓰는 가변 타입

- 필드 심볼이나, DATA ... FIELD-SYMBOLS선언 시,

- 동적으로 구조체의 필드를 참조할 때,

- Assign문과 함께 쓸 떄 사용함

 - 단점으로는 정적 타입체크가 안된다는 점이 있음 

 

Fully Type Field Symbol

- 필드 심볼을 정의할 때부터 타입이 완전히 정해진 형태로 선언

- 필드 심볼의 기술적인 속성은 할당되는 데이터 오브젝트와 같아야함

FIELD-SYMBOLS <fs3> TYPE SFLIGHT.
FIELD-SYMBOLS <fs4> LIKE LINE OF gt_tab.

 

- 필드심볼 <fs3>은 Sflight 테이블과 같은 구조를 가지는 구조체 타이블로 선언됨

- fs4는 인터널 테이블 Gt_tab과 같은 구조를 가지는 LINE타입의 필드심볼을 선언함

- 변수 이름은 메모리 정적인 주소를 가리키고 있다 (변수이름 = 메모리주소)

- fully type을 이용하면 명시적으로 구조체의 필드명을 호출해 사용할 수 있다

MOVE <fs3>-carrid TO <fs4>-carrid.

 

필드 심볼 할당

 

TYPES : BEGIN OF t_line,
	col1 TYPE c,
    col2 TYPE c,
    END OF t_line.
    
DATA : gs_wa TYPE t_line,
gt_itab TYPE HASHED TABLE OF line WITH UNIQUE KEY col1, 
	key(4) TYPE c VALUE 'COL1'.
    
FILED-SYMBOLS <fs> TYPE ANY TABLE.
ASSIGN gt_itab TO <fs>.

 

- 필드 심볼에 오브젝트를 할당하려면 ASSIGN구문을 활용한다.

- ASSIGN구문 3가지 기능 분류

  • - assign 구문의 기본 구조
  • - 구조체 필드를 필드 심볼에 assign
  • - 필드심볼과 casting

 

Assign 구문의 기본구조

1. static assign 

ASSIGN dobj TO <fs>.

- ASSIGN이 성공하면 시스템 변수 sy-subrc는 0, 실패하면 4를 반환함

 

Offset을 이용한 static assign

- 문자열의 특정위치(인덱스)부터 일부만 참조하거나 대입하는 방식 => 위치와 길이가 고정되어있기 때문에 정적 assign이라고 함 

- 인덱스 기반으로 잘라서 사용하는 방법

변수+시작오프셋(길이)

 

1. 문자열 일부 출력

DATA lv_text TYPE string VALUE 'ABCDEFGHIJ'.

WRITE: / lv_text+0(3).   " 결과: ABC
WRITE: / lv_text+3(2).   " 결과: DE
WRITE: / lv_text+5(5).   " 결과: FGHIJ

lv_text+3(2) -> 4번째 문자부터 2글자 출력(인덱스는 0부터 시작)

2. 일부대입(Static assign)

DATA lv_text TYPE c LENGTH 10 VALUE 'ABCDEFGHIJ'.

lv_text+2(3) = 'XYZ'.

WRITE: / lv_text.   " 결과: ABXYZFGHIJ

lv_text+2(3) : 3번째 문자부터 3글자를 XYZ로 교체

 

3. 동적 offset

DATA lv_offset TYPE i VALUE 2.
DATA lv_len    TYPE i VALUE 3.

WRITE: / lv_text+lv_offset(lv_len).  " 동적으로 접근, 결과: XYZ

- runtime에 계산이 되므로 offset에 대한 동적 Offset

 

오프셋을 초과하면 에러가 발생하고 컴파일되지 않는다.

=> ghijkl ghijkl ghijk 가 출력

offset이 0보다 큰 값이 할당된 경우에는 애스터리스크(*)문자를 사용해야한다. => 필드 심볼이 오브젝트 길이를 넘는 것을 방지함 

 

Assign구문의 동적인 사용

- 필드 심볼에 할당하는 필드명을 알 수 없는 경우(프포그램 내에서 동적으로 할당되는 경우) => 동적 assign구문을 이용함

ASSIGN (dobj) TO <fs>.

 

-> 이와 같이 답이 나온다

 

- assign table field to <fs>구문에서 sflight-carrid라는 필드가 존재하므로 sy-subrc = 0값을 반한함

- name1이라는 테이블 필드가 존재지 않으므로 시스템 변수 sy-subrc가 4를 반환함

 

구조체의 필드를 필드 심볼에 Assign

ASSIGN COMPONENT comp of STURCUTURE struc TO <fs>.

- 구조체의 개별 필드를 필드 심볼에 assign할 수 있다.

- 구조체 struc의 comp(필드)를 필드심볼 <fs>에 할당한다. 

 

항목 첫코드 두번째 코드
접근 방법 필드의 순서(index) 필드의 이름(name)
유연성 구조체 필드명 변경돼도 잘 작동함 필드명 규칙이 바뀌면 코드도 수정 필요
용도 필드 순서 기반 처리 명명 규칙이 있는 필드에 유용

 

필드심볼과 casting

- 데이터 오브젝트를 필드심볼에 assign할 경우, cast를 이용해 모든 데이터 타입을 필드심볼에 Assign할 수 있다.

CAST는 암묵적 형 변환과 명시적 형 변환 2가지로 분류되어 사용됨

암묵적 형 변환(Implicit Casting)

- 필드 심볼의 data type : fully type으로 선언되어 있거나 기본 데이터 타입 -c, -n, p, x-를 사용한 경우에 암묵적 형 변환을 사용함

DATA: num TYPE i VALUE 10,
      text TYPE c LENGTH 5.

text = num.  " 정수 10이 문자 '10'으로 자동 변환됨

- 타입이 정해진 필드 심볼과 데이터 오브젝트 타입이 다른 경우에는 cating구문을 사용해 assign해야함

ASSIGN <var> TO <fs> CASTING.

구조체 변환

DATA: gv_addr(30) TYPE c VALUE 'Korea Seoul Twin Building'.

FIELD-SYMBOLS: <fs> TYPE t_line.

ASSIGN gv_addr TO <fs>.  " ❌ 오류 발생!

gv_addr은 단순 문자형_c이고, <fs>는 구조체 t_line이기에 전혀 호환이 안된다. -> 개발자가 명확히 casting한 것으로 알려줘야함!!

 

명시적 형 변환(Explict Casting)

FIELD-SYMBOLS : <f1> TYPE ANY.
=>
ASSIGN ADDR TO <F1> CASTING TYPE line.

casting type구문을 이용해 정해진 타입으로 형 변환을 수행하는 것을 명시적 형 변환이라고 한다.

 

필드심볼과 인터널 테이블

- 변수와 같이 인터널 테이블도 같은 과정으로 필드 심볼에 할당하여 사용할 수 있다.

- 필드 심볼을 이용해 인터널 테이블을 변경하면, Work Area로 복사하는 과정이 생략되기에 성능이 향상된다

 

- FIELD-SYMBOLS를 쓸 때 generic하게 써야하기 때문에 type any table로 써야한다.

 

필드 심볼과 구조체

DATA : BEGIN OF gs_line,
	col1(1) TYPE c,
    col2(1) TYPE c VALUE 'X',
    END OF gs_line.
    
FIELD-SYMBOLS <fs> LIKE gs_line.
ASSIGN gs_line TO <fs>.
MOVE <fs>-col2 TO <fs>-col1.

 

- 필드심볼을 구조체처럼 사용할 경우에는 필드 심볼 선언 시에 LIKE or TYPE을 선언해야함

- 필드 심볼 타입이 이미 정의되어 있다면, 필드 심볼과 기술적 속성이 같은 데이터 오브젝트만이 필드 심볼에 할당될 수 있음을 의미한다.

 

여기서 갑자기 드는 의문

field-symbols와 like line of등과 같은 Work area는 어떻게 다른걸까? 거의 비슷한 역할을 한다고 생각이 들었다.

구분 FIELD-SYMOLS LIKE LINE OF로 선언한 Work Area
개념 “참조 (reference)” “복사된 값 (copy of a row)”
메모리 방식 원본 데이터를 직접 가리킴 내부 테이블의 한 줄 값을 복사해서 저장
수정 시 영향 원본 내부 테이블이 직접 변경됨 Work area만 바뀌고 원본은 변하지 않음
성능 빠름 (복사 없음) 복사 발생 → 약간 느릴 수 있음
유연성 유연하고 동적 처리에 적합 정적이고 단순한 구조에 적합

 

 

LIKE LINE OF 예시

DATA: gt_itab TYPE STANDARD TABLE OF sflight,
      gs_line LIKE LINE OF gt_itab.

LOOP AT gt_itab INTO gs_line.
  gs_line-price = gs_line-price * 2. " 원본에는 영향 X
ENDLOOP.

- gs_line은 복사된 값이기 때문에, gt_itab의 실제 데이터는 수정되지 않는다.

 

FIELD-SYMBOLS 예시

FIELD-SYMBOLS <fs> TYPE sflight.

LOOP AT gt_itab ASSIGNING <fs>.
  <fs>-price = <fs>-price * 2. " 원본 데이터가 직접 바뀜
ENDLOOP.

- <fs>는 원본의 참조이므로 gt_itab의 내용이 직접 변경된다.

- 필드심볼 사용

- 참조처럼 작동해서 메모리를 직접 다룰 수 있음

- ASSIGNING을 써서 자동으로 원본 데이터를 수정할 수 있음 

- 복사 없이 데이터를 바로 다를 수 있음

 

 

- 워크에어리어 사용

- 안정성이 높고, 복사한 구조체기 때문에 실수 방지에 좋음

- 코드가 명확함 

- Modify, append, insert사용

- 매번 복사/복원하기에 성능이 떨어질 수도 있음

 

데이터 참조

PARAMETERS p_tname(30) DEFAULT 'sflight'.

- 사용자가 테이블 이름을 입력할 수 있게 함

- 기본값은 'sflight'. 아무것도 안넣으면 sflight 테이블 기준으로 실행됨

DATA: dref TYPE REF TO data.
FIELD-SYMBOLS: <fsl> TYPE any, <fs2> TYPE any.

- dref : 데이터 객체를 참조(포인터)할 수 있는 변수

- <fs1> : 테이블 구조 전체를 가르키는 필드 심볼

- <fs2> : 한 컬럼의 값을 기키는 필드 심볼

CREATE DATA dref TYPE (p_tname).
ASSIGN dref->* TO <fsl>.

- p_tname에 들어온 테이블명을 기반으로 그 테이블 구조를 동적으로 생성

- 구조를 <fs1> 필드 심볼에 연결(포인터 연결)

SELECT * FROM (p_tname) INTO <fsl> UP TO 3 ROWS.

- 사용자가 입력한 테이블에서 최대 3개의 레코드만 읽어서 <fs1>에 담는다.

- p_tname은 동적 SQL.

DO.
  ASSIGN COMPONENT sy-index OF STRUCTURE <fsl> TO <fs2>.

- <fs1> 구조의 각 필드 컬럼을 순서대로 <fs2>에 할당함

- sy-index는 do루프의 반복번호다.

결과값

 

- 데이터 참조는 데이터 오브젝트를 가리키는 포인터, 필드 심볼을 통해 데이터 오브젝트의 값에 접근한다.

- 프로그램 실행 시점에 데이터 오브젝트는 동적으로 생성되기에 메모리 주소도 동적으로 할당됨

 

🔑 1. 참조 변수 (Reference Variable)

DATA dref TYPE REF TO data.

- 어떤 데이터 오브젝트(객체, 구조체, 테이블 등)의 주소를 저장하는 변수

- dref는 참조 변수

- 어떤 데이터 오브젝트의 주소를 저장하는 변수

- 자체는 데이터를 갖지 않고 있고, 어떤 오브젝트를 가르키는 역할만 함

- 아무것도 가르키지 않은 상태(dref = null 상태)

 

오브젝트연결

 

1) CREATE DATA 또는  GET REFERENCE 등으로 명시적 연결

CREATE DATA dref.           " dref가 가리킬 메모리 공간 동적 생성

 

 2) GET REFERENCE OF  기존 변수 연결

DATA val TYPE i VALUE 100.
GET REFERENCE OF val INTO dref.

- 기존 변수 val의 주소를 dref가 가리킴

 

 연결 가능한 오브젝트들

타입 예시 설명
데이터 객체 DATA val TYPE i. 기본형 값, 구조, 내부 테이블 등
클래스 인스턴스 REF TO zcl_my_class 객체지향에서 클래스 인스턴스를 가리킴
동적 타입 객체 REF TO data, FIELD-SYMBOLS TYPE ANY 실제 타입은 나중에 결정됨
필드심볼 <fs> 간접접근이 가능함

 

  • 참조가 연결되지 않은 상태에서 dref->* 접근 시 → Dump
  • 반드시 IS BOUND 체크하는 습관:
IF dref IS BOUND.
  ASSIGN dref->* TO <fs>.
ENDIF.

 

 

🔁 2. 역참조 (Dereferencing)

ASSIGN dref->* TO <fs>.

- 역참조는 포인터가 가르키는 주소에 저장된 데이터에 접근하는 것으로 정의됨 

- 참조변수는 단지 데이터 오브젝트의 주소만 알고 있고, 실제 데이터를 사용하려면 해당 주소에 접근해야하는데 이걸 역참조라고함

- 즉, 데이터 참조가 가리키는 데이터 오브젝트의 변숫값에 접근하려면 Dereference과정을 거쳐야 한다.

- 필드 심볼에서의 casting 기능도 동일하게 사용할 수 있다.

 

DATA dref TYPE REF TO i.   " 참조변수 선언
CREATE DATA dref.          " 메모리 생성
dref->* = 100.             " 역참조로 값 설정
WRITE: dref->*.            " 역참조로 값 읽기

 

1. 구조(structure) 역참조

TYPES: BEGIN OF ty_line,
         name TYPE string,
         age  TYPE i,
       END OF ty_line.

DATA dref TYPE REF TO ty_line.
CREATE DATA dref.
dref->* = VALUE #( name = 'Wonie' age = 25 ).  " 구조에 값 대입
WRITE: dref->name, dref->age.                 " 각 필드 직접 접근 가능

- 구조는 ->* 없이도 필드에 직접 접근이 가능함 

 

 

2. 내부 테이블 참조와 역참조

TYPES: BEGIN OF ty_line,
         id   TYPE i,
         text TYPE string,
       END OF ty_line.

DATA: itab  TYPE STANDARD TABLE OF ty_line,
      dref  TYPE REF TO data,
      <itab> TYPE STANDARD TABLE.

CREATE DATA dref TYPE STANDARD TABLE OF ty_line.
ASSIGN dref->* TO <itab>.

APPEND VALUE #( id = 1 text = 'Hi' ) TO <itab>.

LOOP AT <itab> ASSIGNING FIELD-SYMBOL(<wa>).
  WRITE: / <wa>-id, <wa>-text.
ENDLOOP.

 

- 여기서 dref->*를 통해 참조 대상 테이블 전체를 itab으로 할당

- <itab>에서 다시 한 줄씩 <wa>로 역참조하여 값 출력

->와 ->* 차이 

연산자 용도
-> 클래스 인스턴스의 메서드나 속성 접근 (객체지향용)
->* 데이터 오브젝트(기본형, 구조형 등) 에 대한 일반 

 

TYPES: BEGIN OF t_struct,
         col1 TYPE char15,
         col2 TYPE char15,
       END OF t_struct.

DATA: dref1 TYPE REF TO data,
      dref2 TYPE REF TO data.

FIELD-SYMBOLS: <fs1> TYPE t_struct,
               <fs2> TYPE char15.

CREATE DATA dref1 TYPE t_struct.
ASSIGN dref1->* TO <fs1>.

- t_struct 라는 구조체를 정의함

- dref1, dref2는 어떤 데이터는 가리킬 수 있는 Generic참조변수

- <fs1>은 구조체 타입 필드 심볼(포인터같은 역할)

- <fs2>는 char15필드를 가리킬 수 있는 필드 심볼

<fs1>-col1 = 'Enjoy abap'.
<fs1>-col2 = 'Abap Programming'.

-  생성된 구조체 인스턴스 필드에 값 저장 (dref1이 가르키는 구조체의 co1, col2)

 

dref2 = dref1 => dref2도 이제 같은 구조체 인스턴스를 같이 가리키게 됨(얕은 복사)

ASSIGN dref2->* TO <fs2> CASTING.
WRITE / <fs2>.

- dref2 -> *는 구조체 전체

- <fs2>는 char15 -> 타입이 달라서 casting 덕분에 첫 필드(col1)만 퉁엳

GET REFERENCE OF <fs1>-col2 INTO dref2.

- col2 필드의 참조를 dref2에 저장

- dref2 -> *는 col2 하나만 가리키는 참조

ASSIGN dref2->* TO <fs2>.
WRITE / <fs2>.

- dref2->*는 이제 col2이므로 문제없이 fs2에 연결되고 출력됨

+ Recent posts