@luzluna - C,Perl 엔지니어. 근래엔 Ops에 더 가까운 DevOps. PostgreSQL 성능 최적화의 공동 역자, luzluna at gmail.com
지난 기사에서 예고했던대로 문자열 "101"
이 들어있는 변수에
정수형 101
이 들어있는 변수를 더하면 어떤 일이 발생하는지 살펴보겠습니다.
Perl 내부 구조 #1 : 스칼라 변수 기사를 읽어 오는 것이 우선이겠군요. :-)
우선 실행할 코드는 다음과 같습니다.
#!/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
라는 새로운 타입으로 바뀌었습니다.
바뀐 후를 조금 더 자세히 살펴보겠습니다.
PVIV
: Pointer Value Integer Value 포인터와 정수형을 모두 저장할 수 있습니다.FLAGS
: IOK
, pIOK
포인터와 정수형을 모두 저장할 수 있지만 지금은 정수형 값을 가지고 있는 상태라고 표시되어 있습니다.IV
: 더해진 후의 값인 202
가 들어있습니다.PV
: 더이상 의미는 없는 과거의 문자열 값인 "101"\0
을 그대로 저장하고 있습니다.조금 더 꼼꼼히 보면 $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)
그대로
변화가 없다는 점을 눈여겨 보세요.
그 외에도 FLAGS
가 IOK
에서 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
로 변했습니다.
여기에서 눈여겨 볼 부분은 PVNV
로 IV
와 NV
, 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
의 값만 없애버린 것을 확인할 수 있습니다.
펄에서 스칼라 변수는 내부적으로 크게 NULL
과 IV
, NV
, PV
4가지 종류가 존재합니다.
그리고 동적인 타입 변환을 위해 PVIV
와 PVNV
라는
두 가지 이상의 타입을 저장할 수 있는 복합 타입을 가지고 있습니다.
IV
는 문자열이 될 때에 PVIV
가 됩니다.IV
는 실수형이 될 때에 PVNV
가 됩니다.NV
는 정수형이 될 때에 PVNV
가 됩니다.NV
는 문자열이 될 때에 PVNV
가 됩니다.PV
는 정수형이 될 때에 PVIV
가 됩니다.PV
는 실수형이 될 때에 PVNV
가 됩니다.보기만해도 어지러워보이네요. 그냥 간단히 정리해보았습니다.
PVIV
는 문자열과 정수를 저장할 수 있습니다.PVNV
는 문자열과 정수 그리고 실수를 저장할 수 있습니다. 그리고 당연히 PVNV
가 가장 무겁겠죠.문자열에 정수를 더한다거나, 숫자에 문자열을 연결한다거나 등의 경우에 변환이 발생하는것은 앞의 예제에서 계속 살펴보았습니다. 하지만 예상치 못하게 필요없는 타입 변환이 발생하는 경우도 있습니다.
별 생각없이 변수를 출력해볼 때 어떤 일이 일어나는지 살펴보죠.
#!/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
호오. NULL
이 NV
로 바뀐 것을 확인할 수 있습니다.
지난 기사에 이어 이번에는 스칼라 타입을 다른 타입으로 변환할 때 무슨 일이 일어나는지 살펴보았습니다. 프로그램의 효율성을 개선할 때 이런 이슈들로 고민할 정도로 극단적인 경우는 거의 없겠지만, 펄은 약간이나마 메모리 효율과 성능을 높이기 위해 이런 부분까지 고민하고 있다라는 사실을 기억하면 좋을 것 같습니다. :)
더 자세한 내용을 알고 싶다면 다음 문서를 참고하세요.
EOT
X-mas tree
& Llama
ASCII Art by ASCII Art Farts.
Computer ASCII Art by Chris.com.
Font ASCII Art by TAAG.
Artwork by
Inkyung Park
& Keedi Kim.
Designed by
Hojung Youn
& Keedi Kim.
Articles by
Seoul Perl Mongers.
Edited by
Luzluna Park
& Keedi Kim.
Hosting generously sponsored by
Yuni Kim.
Sponsored by
SILEX.
.-''' __ __ / \/ \/ \ =-_- | \. -____- / \ // /|| '' //| //|| == = == ==