2015년 6월 19일 금요일

싸이랩(scialb)의 구조체(struct)

구조체는 개별적인 데이터를 하나로 묶는 자료형이며 Scilab에서도 이것을 지원한다. 예를 들어서 어떤 사람의 이름, 나이, 시력을 각각 name, age, sight 라는 이름으로 저장하고 싶다면 다음과 같이 struct()함수를 사용한다.

[그림 1] 구조체의 생성

구조체의 각각의 데이터를 필드(field)라고 칭한다. 이 예에서 person1 구조체의 필드는 name, age, sight 이다. 함수 struct() 은 반드시 짝수 개(0도 가능함)의 입력 인수를 가져야 하고 홀수 번째의 인수는 구조체의 필드 이름으로서 반드시 문자열이어야 한다. 짝수 번째 입력 인수는 진전에 입력된 필드명을 가지는 값으로서 Scilab 객체(행렬, 문자열, 등등)가 온다.

 위와 같은 구조체를 정의하는데 있어서 또 다른 방법은 개별적인 요소를 하나하나 직접 생성/입력하는 방법이 있다. 두 가지 문법이 있는데 다음과 같다.

structName(‘fieldName’)
structName.fieldName
    
두 가지 방법에는 큰 차이점이 있다. 전자의 경우는 필드명에 임의의 문자열을 사용할 수 있으나 후자의 경우는 일반적인 식별자 규칙을 따라야 한다는 것이다.

[그림 2] 구조체의 생성 (다른 방법)

구조체의 필드를 접근한다던가 아니면 추가하는데 있어서도 위에서 설명한 바와 같이 두 가지 방법이 있다. 예를 들어서 age필드를 접근하려면

a = person1.age // 읽기
person1.age = 43 // 변경
a = person1(‘age’) // 읽기
person1(‘age’) = 43 // 변경

새로운 필드도 자유롭게 추가할 수 있다.

person1.height = 170  // height라는 새로운 필드 추가
person1(‘height’)=170 //위와 동일함

 만약 두 개 이상의 구조체가 서로 같은 필드 이름들을 가지고 있다면 이것들을 하나의 행렬로 묶을 수 도 있다.

[그림 3] 구조체를 요소로 가지는 행렬

이 예제에서 구조체 sA와 sB는 똑같은 필드명을 가지고 있으므로 하나의 행렬로 묶을 수 있다. 필드의 값은 데이터형이 서로 달라도 상관없으며 중요한 것은 필드명이다. 필드명이 다른 두 구조체를 하나의 행렬로 묶으려고 한다면 에러를 발생한다.

 한 가지 알아야 할 것은 한 구조체에서 다른 구조체로 대입을 할 때 Scilab에서는 구조체의 내용물이 복사되는 것이지 참조가 되는 것은 아니라는 것이다. 위의 예에서

sC = sA

라고 하면 sC 변수에는 sA의 모든 구조체 필드들이 “복사된” 새로운 구조체가 생성되는 것이다. 따라서 이후에

sA.c = [1 0]

이라고 sA에 새로운 필드를 추가한다고 해서 sC에 영향을 미치지는 않는다. 이것은 구조체를 함수에 넘길 때도 마찬가지로 적용되는데 함수 내부에서 넘겨받은 구조체를 변형시킨다고 해도 원래의 구조체와는 아무런 상관이 없다는 것을 알아두어야 한다.

 구조체와 관련된 함수들은 다음과 같다.

[표 1] 구조체와 관련된 함수들
함수명
기능
struct(...)
구조체 생성
isstruct(s)
s가 구조체인지 테스트
isfield(s,f)
f가 s의 필드인지 테스트
length(s)
사용자 필드 수 + 2
fieldnames(s)
getfield(n, s)
구조체 s의 필드명을 문자열 행렬로 반환
구조체 s의 n번째 필드값을 반환
setfield
(사용 빈도가 매우 낮을 것 같음)
s = null()
구조체 s 삭제

여기서 getfiled() 함수는 구조체의 필드명을 문자열벡터로 반환하는데 3번째 요소부터 사용자 필드라는 것에 유의해야 한다. 아래 예를 보자.

[그림 4] getfiled()함수의 반환 객체

이 예에서 getfield()함수의 첫 번째 인자는 s1의 자료형이 구조체임을  나타내는 문자열이고 (내부적으로 구조체는 mlist 임.) 두 번째 인자인 dim은 Scilab에서 자동으로 생성하는 필드이다. 따라서 사용자 필드는 세 번째부터 마지막까지이다. 사용자 필드명만 뽑아내려면 다음과 같이 하면 될 것이다.

>> fields = getfield(1, s1)
>> fields = fields(3:$)

또는 간단하게 fieldnames()함수를 사용하면 된다.

>> fields = fieldnames(s1)

만약 사용자의 첫 번째 필드인 s1.A 의 값을 읽어내려면 다음과 같이 하면된다.
    
[그림 5] getfield()함수

이 내용은 혼동하기 쉬운데 이렇게 이해하면 될 것 같다. getfield(n, s) 함수는 구조체 s의 내부적인 필드”값”를 반환하는데 내부적으로 s구조체의 첫 번째 필드는 모든 필드명의 문자열벡터, 두 번째 필드는 dims, 세 번째 필드부터가 사용자 필드이다. 따라서 해당되는 것을 반환하는 것이다. 만약 위에서 예를 든 s1의 경우에는 다음 표와 같이 내부적인 데이터를 가진다.

[표 2] getfiled() 함수 반환 객체의 내부 인덱스
내부 인덱스
필드명
필드값
(getfield 함수의 반환값)
1

[ ‘st’ , ‘dims’, ‘A’, ‘b’ ]
2
‘dims’
[1 1]
3
‘A’
[1 2; 3 4]
4
‘b’
[0 1]

따라서 getfield(3, s1) 이라고 하면 s1구조체의 3번째 필드의 필드값이 반환된다고 이해하면 된다.

 하지만 구조체의 필드를 접근하는 데에는 getfield()함수나 setfield()함수를 이용하는 것 보다는 dot(.) 연산자나 문자열키로 읽거나 쓰는 방식이 더 일반적이다.

댓글 없음:

댓글 쓰기