엑셀 VBA에서 Variant
형은 “무엇이든 담을 수 있는 그릇”이다. 이 글에서는 Variant형의 동작 원리, 메모리 구조, 속도·안정성에 미치는 영향, 주의해야 할 함정을 실무 위주로 정리하여, 잘못 사용했을 때 발생할 수 있는 오류와 성능 저하를 예방하고자 한다.
1. Variant형이란 무엇인가?
Variant는 VBA의 기본(암시적) 데이터형으로, 숫자·문자·Object·배열·Null·Error까지 모두 보관할 수 있다. 내부적으로는 16바이트 Fixed Header + 가변 데이터 구조로 동작하며, SubType(Tag) 필드를 통해 현재 담긴 실제 형식을 결정한다.
구성 요소 | 크기(바이트) | 설명 |
---|---|---|
Type Descriptor | 2 | 현재 저장된 서브타입 코드(예: 2 = Integer, 8 = String) |
Flag | 2 | ByRef 여부, Array 여부 등 메타 정보 |
Data(포인터 또는 값) | 8 | 정수·Long·Double 등은 값 그대로, String·Object·배열은 포인터 |
Reserved | 4 | 런타임용 예약 영역 |
Tip Variant 배열(Dim v()
)은 Variant Header가 다시 요소마다 중첩되므로, 고정형 배열보다 메모리 부담이 크다.
2. 장점
- 유연성 : 데이터형을 미리 모를 때(예: 유저 입력, ADO 레코드셋) 즉시 저장·처리 가능하다.
- 쉬운 문자열 결합 : 숫자 + 문자 등을 & 연산으로 간단히 이어 붙일 수 있다.
- Null·Empty·Error 상태 전달 : 데이터베이스 Null, 미입력(Empty), 오류(Error)를 그대로 보존해 로직에서 분기 처리할 수 있다.
3. 주의점 및 성능 이슈
3-1) 암시적 형 변환 오버헤드
Variant는 연산 시마다 타입 해석 → 필요 시 변환 → 계산 → 재포장 과정을 거친다. 반복 루프 내부에서 숫자 덧셈처럼 자주 호출되는 부분에 Variant를 쓰면, 정수형(Long
) 대비 3 ~ 15배까지 느려진다.
'느린 예시
Dim v1 As Variant, v2 As Variant, i As Long
v1 = 1: v2 = 2
For i = 1 To 1E6
v1 = v1 + v2 '타입 해석 반복
Next i
3-2) 메모리 사용량 증가
정수 한 개(Long
)는 4바이트지만, Variant는 최소 16바이트 헤더 + 4바이트 값 = 20바이트를 차지한다. 대용량 배열·딕셔너리에서 Variant를 쓰면 예상보다 메모리가 급증한다.
3-3) Null, Empty, ""(빈 문자열) 혼동
상태 | 판별 함수 | 의미 | 테스트 예시 |
---|---|---|---|
Empty | IsEmpty |
초기화되지 않음 | Dim v: IsEmpty(v)=True |
Null | IsNull |
“값 없음” (DB Null) | v = Null |
"" | Len(v)=0 |
길이 0 문자열 | v = "" |
Null을 산술 연산에 사용하면 결과가 Null
이 되므로, 합계 계산 시 Nz 함수 또는 Null 검사가 필수이다.
3-4) Option Explicit 의무화
변수를 선언하지 않으면 VBA는 Variant
로 간주한다. Option Explicit를 통해 암시적 Variant 사용을 막아야 오타·런타임 오류를 줄일 수 있다.
3-5) Variant + Date 서브타입 주의
날짜 계산에서 서브타입이 Date인지 Double인지 헷갈리면, 국가 설정(로캘) 교차 시 서식 오류가 발생한다. CDate, CLng, Format
으로 명시 변환 후 저장·출력한다.
4. 안전하게 사용하는 6가지 실전 팁
- 초기값을 명시 :
Dim v As Variant: v = Empty
처럼 초기 상태를 결정한다. - 계산용 변수는 고정형 : 합계·카운트는
Long
,Double
을 사용 후 결과만 Variant에 저장한다. - 배열에는 고정형 요소 지정 :
Dim arr() As Double
로 선언해 변환비용을 없애고, 필요 시 Variant 배열로 ReDim Preserve 하지 않는다. - IsEmpty / IsNull / VarType 로 검사 : 상태별로 다른 함수를 사용해 의도치 않은 분기 오류를 막는다.
- ByRef 매개변수는 형 따로 선언 : 프로시저 인수는
ByVal v As Variant
로 받더라도 내부에서Dim d As Double: d = CDbl(v)
로 고정. - Debug.Print VarType(v) : 디버깅 단계에서 서브타입(예: 8=String, 7=Date)을 출력해 실시간 확인한다.
5. 실무 예제: 폼 입력값 자동 형 변환
사용자가 폼에 입력한 데이터를 검증 후 적절한 형으로 저장하는 예시이다.
Function NormalizeValue(raw As Variant) As Variant
If IsNull(raw) Or IsEmpty(raw) Then
NormalizeValue = Null 'DB Null 처리
ElseIf IsNumeric(raw) Then
NormalizeValue = CDbl(raw) '숫자는 Double
ElseIf IsDate(raw) Then
NormalizeValue = CDate(raw) '날짜는 Date
Else
NormalizeValue = CStr(raw) '기타는 문자열
End If
End Function
이처럼 초기에 서브타입을 고정해 두면, 이후 쿼리·계산 시 조건 분기가 단순화된다.
FAQ
Q. Variant를 완전히 쓰지 않을 수 있나요?
A. 레거시 코드·폼·데이터베이스 Null 처리에는 Variant가 편리하다. 다만 루프·대용량 배열·수치 연산에서는 반드시 고정형으로 캐스팅해 성능을 확보한다.
Q. Variant 메모리 관리가 어려운데, 종료 후 자동 해제되나요?
A. 프로시저 종료 시 Variant Header는 스택에서 사라지지만, 내부 포인터(String, Object, 배열)는 참조 카운트 0이 되어야 해제된다. Set Nothing, Erase 등을 적시에 호출하라.
Q. Variant 배열에서 Null 과 Empty 를 구분하려면?
A. 루프 돌면서 If IsEmpty(arr(i)) Then … ElseIf IsNull(arr(i)) Then …
형태로 별도 분기해야 한다. WorksheetFunction.CountA는 Null을 무시하지 않으므로 주의한다.
'#4 VBA > #4.2 코딩문법' 카테고리의 다른 글
Boolean형과 논리연산자(And, Or 등) (2) | 2025.08.07 |
---|---|
문자형(String)과 문자열 연결(&) (3) | 2025.08.06 |
데이터형(Integer, Long, Double 등) 구분 (3) | 2025.08.05 |
상수(Constant) 선언 방법 (0) | 2025.08.04 |
전역 변수와 지역 변수 차이 (7) | 2025.07.31 |