아홉째 날: Perl 내부 구조 #2 : 스칼라 변수 업그레이드

저자

@luzluna - C,Perl 엔지니어. 근래엔 Ops에 더 가까운 DevOps. PostgreSQL 성능 최적화의 공동 역자, luzluna at gmail.com

시작하며

지난 기사에서 예고했던대로 문자열 "101"이 들어있는 변수에 정수형 101이 들어있는 변수를 더하면 어떤 일이 발생하는지 살펴보겠습니다.

준비물

Perl 내부 구조 #1 : 스칼라 변수 기사를 읽어 오는 것이 우선이겠군요. :-)

"101" + 101

우선 실행할 코드는 다음과 같습니다.

#!/usr/bin/env perl

use Devel::Peek;

$str = "101";
Dump($str);
$int = 101;
$str = $str + $int;
Dump($str);

실행 결과는 다음과 같습니다.

SV = PV(0x83b1b00) at 0x83b16a8
  REFCNT = 1
  FLAGS = (POK,pPOK)
  PV = 0x83c7300 "101"\0
  CUR = 3
  LEN = 4
SV = PVIV(0x83b2b10) at 0x83b16a8
  REFCNT = 1
  FLAGS = (IOK,pIOK)
  IV = 202
  PV = 0x83c7300 "101"\0
  CUR = 3
  LEN = 4

더하기 전에는 PV 타입으로 길이 4짜리 "101"\0이 저장되어 있습니다. 하지만 더한 직후에 덤프 결과를 보면 PVIV라는 새로운 타입으로 바뀌었습니다. 바뀐 후를 조금 더 자세히 살펴보겠습니다.

조금 더 꼼꼼히 보면 $str 심볼의 주소는 at 0x83b16a8으로 변화가 없지만, 실제 값이 저장되는 공간은 PV(0x83b1b00)에서 PVIV(0x83b2b10)0x10 바이트만큼 이동한 것을 알 수 있습니다.

다시 문자열로

PV에서 PVIV 타입의 정수형으로 변환된 변수를 다시 문자열로 바꾸면 어떻게 될까요?

#!/usr/bin/env perl

use Devel::Peek;

$str = "101";
Dump($str);
$int = 101;
$str = $str + $int;
Dump($str);

$str = "$str test";
Dump($str);

실행 결과는 다음과 같습니다.

SV = PV(0x9d1db00) at 0x9d1d6a8
  REFCNT = 1
  FLAGS = (POK,pPOK)
  PV = 0x9d332f8 "101"\0
  CUR = 3
  LEN = 4
SV = PVIV(0x9d1eb10) at 0x9d1d6a8
  REFCNT = 1
  FLAGS = (IOK,pIOK)
  IV = 202
  PV = 0x9d332f8 "101"\0
  CUR = 3
  LEN = 4
SV = PVIV(0x9d1eb10) at 0x9d1d6a8
  REFCNT = 1
  FLAGS = (POK,pPOK)
  IV = 202
  PV = 0x9d332f8 "202 test"\0
  CUR = 8
  LEN = 12

$str의 위치는 당연하게도 at 0x9d1d6a8로 변경되지 않습니다. 실제 값이 저장되는 위치는 문자열에서 정수형으로 변할 때 PV(0x9d1db00)에서 PVIV(0x9d1eb10)으로 변경되었지만, 다시 문자열이 될 때에는 PV로 바뀌지 않고 PVIV(0x9d1eb10) 그대로 변화가 없다는 점을 눈여겨 보세요.

그 외에도 FLAGSIOK에서 POK로 변경되었습니다. IV는 의미 없는 값인 202를 그대로 저장하고 있습니다.

문자열을 실수로 바꾸면?

문자열을 정수형대신 소숫점을 붙혀서 실수형으로 바꾸면 어떻게 되는지 살펴보겠습니다.

#!/usr/bin/env perl

use Devel::Peek;

$str = "101";
Dump($str);

$str = $str + 1.01;
Dump($str);

실행 결과는 다음과 같습니다.

SV = PV(0x1d7ad80) at 0x1d8ea30
  REFCNT = 1
  FLAGS = (POK,pPOK)
  PV = 0x1d87a90 "101"\0
  CUR = 3
  LEN = 16
SV = PVNV(0x1d79570) at 0x1d8ea30
  REFCNT = 1
  FLAGS = (NOK,pNOK)
  IV = 0
  NV = 102.01
  PV = 0x1d87a90 "101"\0
  CUR = 3
  LEN = 16

이번엔 PVNV로 변했습니다. 여기에서 눈여겨 볼 부분은 PVNVIVNV, PV를 모두 가지고 있다는 점 입니다.

변수를 초기화하면?

변수를 초기화하면 어떤 일이 일어날까요?

#!/usr/bin/env perl

use Devel::Peek;

$str = 101;
Dump($str);
undef $str;
Dump($str);

실행 결과는 다음과 같습니다.

SV = IV(0x782a20) at 0x782a30
  REFCNT = 1
  FLAGS = (IOK,pIOK)
  IV = 101
SV = IV(0x782a20) at 0x782a30
  REFCNT = 1
  FLAGS = ()
  IV = 101

NULL 타입으로 바꾸지 않고 그냥 FLAGS의 값만 없애버린 것을 확인할 수 있습니다.

중간 정리

펄에서 스칼라 변수는 내부적으로 크게 NULLIV, NV, PV 4가지 종류가 존재합니다. 그리고 동적인 타입 변환을 위해 PVIVPVNV라는 두 가지 이상의 타입을 저장할 수 있는 복합 타입을 가지고 있습니다.

보기만해도 어지러워보이네요. 그냥 간단히 정리해보았습니다.

변환이 발생하는 경우

문자열에 정수를 더한다거나, 숫자에 문자열을 연결한다거나 등의 경우에 변환이 발생하는것은 앞의 예제에서 계속 살펴보았습니다. 하지만 예상치 못하게 필요없는 타입 변환이 발생하는 경우도 있습니다.

별 생각없이 변수를 출력해볼 때 어떤 일이 일어나는지 살펴보죠.

#!/usr/bin/env perl

use Devel::Peek;

$str = 101;
Dump($str);

print $str . "\n";
Dump($str);

실행 결과는 다음과 같습니다.

SV = IV(0x205da20) at 0x205da30
  REFCNT = 1
  FLAGS = (IOK,pIOK)
  IV = 101
101
SV = PVIV(0x2061c40) at 0x205da30
  REFCNT = 1
  FLAGS = (IOK,POK,pIOK,pPOK)
  IV = 101
  PV = 0x2056a90 "101"\0
  CUR = 3
  LEN = 16

단지 숫자를 출력하고 싶었을 뿐인데 PVIV로 변해버렸습니다. 이 경우 다음과 같이 바꿔주면 변환이 이루어지질 않습니다.

#!/usr/bin/env perl

use Devel::Peek;

$str = 101;
Dump($str);

print $str, "\n";
Dump($str);

실행결과는 다음과 같습니다.

SV = IV(0xb78a20) at 0xb78a30
  REFCNT = 1
  FLAGS = (IOK,pIOK)
  IV = 101
101
SV = IV(0xb78a20) at 0xb78a30
  REFCNT = 1
  FLAGS = (IOK,pIOK)
  IV = 101

비교 연산자를 사용할 때는 어떨까요?

#!/usr/bin/env perl

use Devel::Peek;

$str;
Dump($str);

if ( $str == 0 ) {}
Dump($str);

실행 결과는 다음과 같습니다.

SV = NULL(0x0) at 0x21c9a30
  REFCNT = 1
  FLAGS = ()
SV = NV(0x21ec880) at 0x21c9a30
  REFCNT = 1
  FLAGS = ()
  NV = 0

호오. NULLNV로 바뀐 것을 확인할 수 있습니다.

정리하며

지난 기사에 이어 이번에는 스칼라 타입을 다른 타입으로 변환할 때 무슨 일이 일어나는지 살펴보았습니다. 프로그램의 효율성을 개선할 때 이런 이슈들로 고민할 정도로 극단적인 경우는 거의 없겠지만, 펄은 약간이나마 메모리 효율과 성능을 높이기 위해 이런 부분까지 고민하고 있다라는 사실을 기억하면 좋을 것 같습니다. :)

참고문헌

더 자세한 내용을 알고 싶다면 다음 문서를 참고하세요.

EOT

blog comments powered by Disqus