[PL] Data Types
'프로그래밍 언어' 시리즈
- [PL] Preliminaries
- [PL] Names, Bindings, Type Checking, and Scopes
- [PL] Data Types
- [PL] Expressions and the Assignment Statement
- [PL] Statement-Level Control Structures
- [PL] Subprogram
- [PL] Implementing Subprograms
- [PL] Exception Handling and Event Handling
- [PL] Abstract Data Types and Encapsulation Concepts
- [PL] Object-Oriented Programming
✦ Introduction
- 원래 기계어에는 type 이 존재하지 않음
- 프로그래머가 쉽게 사용하도록 여러 data type 지원
◆ Data Type
- 가능한 값 (value) 들의 집합
- 값들에 대해 수행 가능한 연산 (operation) 의 집합
- real-world 의 문제 영역과 얼마나 잘 맞는가?
- language 마다 다양한 data type 존재
✦ Primitive Data Types
- Hardware 적으로 지원해주는 언어
- 기계어로 다룰 수 있음
◆ Numeric Types
- Integer
- 대부분의 컴퓨터 (CPU) 는 여러 size 의 정수를 지원한다
-
word size 와 다르게 compile 될 수 있다

int: 64-bit 지만 32-bit sizepointer: 64-bit → 주소의 길이가 8 byte - 구현- binary sequence 로 표현.
- 가장 왼쪽 비트 (MSB, Most Significant Bit) → 부호 (Sign) 나타냄
- 2’s complement 방식 사용

- Floating-Point
- fraction + exponent 로 표현
- 실수를 모델링 → 정확 X, approximation (근사) 만 가능
- 구현 : by binary
- Sign bit : 부호를 나타내는 bit
- exponent (지수)
- fraction (가수)
- bit 를 더 많이 사용할 수록 더욱 근사해진다

- IEEE Floating-Point 표준
- Decimal
- BCD (Binary Coded Decimal) : 10진수 각 자리를 4 bit 이진수로 표현
- 장점 : 정확한 표현
- 단점 : 16개 표현 가능한데 10개 밖에 표현 안함 → 메모리 낭비
◆ Boolean Types
- True / False - 두 가지 값만 존재
- 구현 : single bit 로만도 표현 가능, but byte 로 저장
◆ Character Types
- 문자 → 숫자 코드 형태로 저장
- ASCII : 1 byte (0 ~ 127)
- Unicode
✦ Character String Types
- non-primitive data type : 하드웨어적으로 지원하진 않으나, 프로그램 writability 위해 언어적으로 지원
- Design Issue
- 언어에서 기본적오로 제공할 것인가? 아니면 char 의 array 인가? (C언어)
- 문자열의 길이는 static? dynamic?
- Examples
- C / C++ : 기본 타입 X, library 로 제공
- Perl, JavaScript, Ruby, PHP → language 레벨에서 string 제공
◆ Primitives or Character Array
- Special kind of character array
- 단일 문자의 배열로 저장
- C에서 string 은 char 의 array 인데 끝에
\0(null) 이 있는 것
- Primitive data type
- 언어 자체에서 string type 제공 → writability 제공
- 여러 operation 제공 (assignment, relational operators, catenation, 부분 문자열 참조 등)
◆ String Length Options
- Static length string
- 선언 시 static 하게 길이 저장.
- 한 번 저장 후 변경 불가
- Dynamic length string
- 최대 제한 X, 다양한 길이 허용
- assign 할 때 마다 길이 설정
- assign 할 때마다 allocation 으로 overhead 발생 → 각자 tradeoff 있음
◆ Evaluation
- string type → 언어의 writability 에 중요
- string 은 그렇게 costly 하지 않으니 구현하면 좋다!
◆ Implementation
- Descriptor : 변수의 attribute 들 모음
- Compile-time discriptor
- Static 문자열
- compile 때 만들어진 정보를 가지고 있음
- Run-time discriptor
- Limited Dynamic 문자열
- 수행 도중의 정보를 가지고 있음
- Compile-time discriptor
- dynamic allocation 방법
- linked list 로 저장 (연속 X)
- 인접 memory cell 로 저장
- 더 커질 때 그대로 복사 해야 함
- 빠른 참조, 적은 저장공간, allocation 이 slow
✦ User-Defined Ordinal Types
- Ordinal (서수) : 가능한 값들의 범위를 양의 정수 집합과 연관 짓는 데이터 타입
- 서수를 이용해 프로그래머가 만든 타입
- Readability 가 좋아짐
◆ Enumeration Type
- 열거형 타입 : symbolic constant 가 순서대로 나옴
- ex)
type DAYS is (Mon, Tue, Wed, Thu, Fri, Sat, Sun) ;
type WEKEND is (Sat, Sun) ;
int i;
DAYS a;
a = Mon;
- DAYS 는 Mon, Tue, Wed, Thu, Fri, Sat, Sun 중 하나의 값 가질 수 있음
- in C, C++
enum day {sun, mon, tue, wed, thr, fri, sat} d1, d2;
- sun, mon, tue, wed, thr, fri, sat 값 가질 수 있는 변수 d1, d2 선언
- 실제 구현될 때에는 integer 로 바뀌어 수행
- 순서 비교 가능
- 산술 연산은 불가능
- range error 쉽게 찾을수 있음
- Operation : Predecessor, Successor, Position, Values
◆ Subrange type
- 어떤 type 의 일부만 접근해서 사용하고 싶을 때
- readability, reliability ↑
- ex)
type
uppercase = 'A'..'Z';
index = 1..100;
- C/C++ 에선 존재하지 않음
◆ Implementation
- Enumeration : 음이 아닌 정수와 연결 (0 ~ )
- Subrange : parent 타입과 동일하게 구현 + range check
✦ Array Types
- 동일 type 데이터들을 묶은 것
- 수학의 vector, matrix 같은 것들 표현 위해 만듬
- 개별 원소는 첫 번째 원소의 상대적 위치 (position) 로 식별
- cf)
record: 데이터 묶은 것. but type 달라도 됨 - Design Issue
- index 로 어떤 type 이 가능한가?
- array 의 size 가 언제 결정되는가? (subscript binding)
- storage allocation 은 언제 결정되는가? (memory binding)
- slice 를 허용하는가?
◆ Arrays and Index
- 대부분의 언어는
a[10]과 같이 원소에 접근한다배열이름[index]
- array → 일종의 mapping 함수
[]대신()를 사용하는 언어도 존재한다
◆ Subscript Binding and Array Categories
- index 로 어떤 데이터 type 이 올 수 있나? (int, boolean, enumeration, subrange)
- C 에선
int나enum사용
- C 에선
- index 의 시작
- 0 또는 1
- C에선 index의 시작으로
0사용
- subscript value binding (array size) / storage binding (memory 할당)
- Static array
- value range & storage 모두 compile time 에결정
- ex) FORTRAN → recursion X
- 장점 : 빠르다
- Fixed stack-dynamic array
- range 는 compile time, storage 는 run time 에 stack 영역에 할당
- 장점 : space efficiency
- ex) C 에서의 일반 array
- Fixed heap-dynamic array
- range & storage 모두 run time 에 memory 는 heap 영역에 할당
- 중간에 크기 변경 X
- ex) C 의
malloc
- Heap dynamic array
- range & storage 모두 run time 에 memory 는 heap 영역에 할당
- 중간에 크기 변경 O
- ex) C 의
realloc
- Static array
| range binding | storage binding | |
| Static array | compile time | compile time |
| Fixed stack-dynamic array | compile time | run time |
| Fixed heap-dynamic array | run time (변화 X) | run time |
| Heap dynamic array | run time (변화 可) | run time |
- 언어마다 제공하는 array 종류가 다름
◆ Heterogeneous Array
- 여러 data type 을 모은 array
record와 차이점- array 는 index 로 접근
- record 는 name 으로 접근
- 대부분 heap dynamic 하게 구현
◆ Number of Subscripts in Array
- 과거에는 3차원까지만 표현 가능
- 현재는 차원에 제한이 없다
- C언어는 엄밀히 1차원. but 배열 자체가 또 다른 배열을 요소로 가질 수 있음 → multidimensional array
- Orthogonal design
◆ Array Initialization
- C
- static array → 초기화 가능
- dynamic array → 초기화 불가능
int list_t[] = {4, 5, 7, 83};
char name[] = "Nang Jongho";
char *names[] = {"Mike", "Fred", "Mary Lou"};
- 초기화 불가능한 언어 / 독특하게 초기화 하는 언어 존재
- Python → list comprehension
- compact, but readability ↓
◆ Array Operation
- 가장 기본적인 operation : 원소 가져오기
- language 마다 구현된 operation 다름
- assignment, arithmetic, relation, logical
- arithmetic → 사칙연산이 overloading 되어 있음
- ex) APL
+.*→ inner product
◆ Type of Array
- Rectangular array : ㅁ 모양, 모든 행 / 열 마다 동일한 개수 요소 가짐
- Jagged matrix / array : 각 행마다 가진 요소의 개수 다름
◆ Slice
- numpy
a = np.array([1,2,3])
b = np.array([4,5,6])
# 각 요소 더하기
c = a + b
c = np.add(a, b)
# c = [5 7 9]
# 각 요소 빼기
c = b - a
c = np.subtract(a, b)
# c = [3 3 3]
# 각 요소 곱하기
c = a * b
c = np.multiply(a, b)
# c = [4 10 18]
# 각 요소 나누기
c = a / b
c = np.divide(a, b)
# c = [0.25 0.4 0.5]
list1 = [
[1, 2],
[3, 4]
]
list2 = [
[5, 6],
[7, 8]
]
a = np.array(list1)
b = np.array(list2)
# matrix 곱하기
c = np.dot(a, b)
# c = [[19 22]
# [43 50]]
a = np.array([[1, 2], [3, 4]])
# array 값 더하기
s = np.sum(a) # 10
# axis = 0 -> column 끼리 더하기
# axis = 1 -> row 끼리 더하기
s = np.sum(a, axis = 0)
# s = [4 6]
# array 값 곱하기
s = np.prod(a) # 24
◆ Implementation
- Single-dimensioned array
address(list[k]) = address(list[1]) + (k-1) * element_size = (address(list[1]) - element_size) + (k * element_size)
(address(list[1]) - element_size) 는 상수 → compile time 에 계산 가능
- Multidimensional array
- memory 는 1차원 → 다차원 array 저장 시 memory 에는 1차원으로 바꿔 저장
- row major order (→)
- 일반적으로 사용
- column major order ( ↓ )
- Example
| 3 | 4 | 7 |
| 6 | 2 | 5 |
| 1 | 3 | 8 |
- row major : 3 4 7 / 6 2 5 / 1 3 8
- column major : 3 6 1 / 4 2 3 / 7 5 8 > location(a[i][j]) = (address of a[1, 1] - ((n + 1) * element_size) + ((i * n + j) * element_size)
→ 그 이전까지의 모든 주소값 계산
✦ Associative array
- 보통 array 는 index 로 요소 접근
- Associative array 는 사용자가 정의한
key를 통해 value 를 찾음 - 각 원소는 (
key,value) 쌍으로 구성 & unordered - readability 향상
- Python : 기본 자료구조
- C++, Java, C# : library 로 제공
✦ Record Types
- 서로 다른 type 의 데이터를 모은 타입
- cf) array 는 type 이 같은 데이터를 모음
- 원소를 이름 (name) 을 통해 접근 (ex.
employee.name.first) - Example
- COBOL (nested)
01 EMPLOYEE-RECORD.
02 EMPLOYEE-NAME.
05 FIRST PICTURE IS X(20).
05 MIDDLE PICTURE IS X(10).
05 LAST PICTURE IS X(20).
02 HOURLY-RATE PICTURE IS 99V99.
- `MOVE CORRESPONDING`
- 두 레코드에서 같은 이름을 가진 필드끼리만 자동 복사
◆ Implement
- 각 필드들은 인접한 memory 공간에 순서대로 저장된다
- word alignment : 성능을 위해 메모리 주소가 4의 배수 (만약 8 byte 짜리 type 있으면 8의 배수) 가 되도록 padding 넣음
- ex)
struct aa {
char c; // 1 byte
int i; // 4 byte
} a;
| 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 |
|---|---|---|---|---|---|---|---|
| c | pad | pad | pad | i | i | i | i |
- 실행 속도 ↑ 프로그램 실행 자체에는 문제 없음
✦ List Type
- Python List
- Python 에서 list 는 array 역할도 함 (사실상 heterogeneous array)
- 다른 언어와는 달리 가변 → 수정 가능
- 원소는 어떤 type 이라도 다 가능!
# 리스트 생성
myList = [3, 5.8, "grape"]
# 원소 접근 (index 는 0부터)
x = myList[1] # x = 5.8
# 원소 삭제
del myList[1]
- List Comprehension
- 수학의 집합 표기법에서 유래
[x * x for x in range(7) if x % 3 == 0]
# [0, 9, 36]
[x * x for x in range(6) if x % 3 == 0]
# [0, 9]
✦ Union Types
- 같은 memory 공간에 서로 다른 type 의 값이 번갈아 저장 가능한 자료 구조
- Storage allocation
- 크기 가장 큰 변수 기준 공간 잡고, 나머지는 앞부분만 사용
- Example
type shape = (circle, triangle, rectangle) ;
object =
record
case form : shape of
circle : (diameter : real) ;
triangle : (leftside : integer; rightside : integer; angle : real) ;
rectangle : (side1 : integer; side2 : integer)
end ;
var thing : object

◆ Implementation
- Discriminated union → 모든 가능한 variant 가 같은 주소 사용
- 제일 큰 변수에 storage 크기 맞추기
- Example
- Ada
type NODE (TAG : BOOLEAN) is
record
case TAG is
when TRUE => COUNT : Integer
when FALSE => SUM : char
end case;
end record;
- `TAG` 가 `TRUE` 면 `COUNT(Integer)` 필드 사용 → 이만큼 공간 할당
- `TAG` 가 `FALSE` 면 `SUM(char)` 필드 사용 → 같은 memory 주소 공유

tag사용 → 현재 저장되어 있는게 어떤 type 인지 나타내는 값- tag 또한 하나의 저장 공간을 차지한다.
- Safety issue 있음
✦ Set type
- 같은 type 값을 unordered & 중복 X 하게 모은 자료 구조
- set 의 최대 원소 개수는?
◆ Implementation
- 메모리에서 bit string 으로 저장
- 합집합 : OR
- 교집합 : AND
✦ Pointer and Reference Types
- Pointer : 변수의 값이 memory address (아무것도 가리키지 않음
nil) - 용도
- 간접 주소 지정 (indirect addressing) : 다른 변수 가리킴
- 동적 메모리 관리 (dynamic storage management) : heap 메모리 할당 / 해제
◆ Pointer Operation
- Assignment (대입) : pointer 에 address 저장
- C 에서
&
- C 에서
int *aa, bb, cc; // aa 만 포인터 변수
aa = &bb; // aa에 bb의 주소 저장
- Dereferencing (역참조) : pointer 가 가리키는 곳의 값을 가져옴
- C 에서
*
- C 에서
cc = *aa; // cc에 aa가 가리키는 bb의 값 저장

- pointer 의 arithmetic 연산 (+ / - )
char *c;
int *i;
*(c + 1) /* c가 가리키는 곳에서 1바이트 앞 */
*(i + 1) /* i가 가리키는 곳에서 4바이트 앞 */
◆ Pointer 의 문제접
- Type Checking
- Dangling Pointer :
free된 동적 변수 주소를 가리키고 있는 포인터
int *i;
sub1() {
int j;
j = 5;
i = &j;
}
*i = ??
- Lost Object
- 잃어버린 객체 (Garbage)
- 접근 불가하지만 메모리 공간 차지 중인 동적 개체
→
free불가 & 사용 불가 → memory leak (메모리 누수)
char *c;
c = malloc(...); /* 첫 번째 할당 */
...
c = malloc(...); /* 두 번째 할당 — 첫 번째 주소를 잃어버림 */
◆ Implementation
- pointer → word size
- Dangling Pointer 해결법
- Tombstone Approch (묘비석 방식)
- 모든 동적 변수에 tombstone 이라는 중간 cell 둠.
- pointer 는 변수를 직접 X tombstone 가리킴
- 동작 방식
- 동적 변수 할당 → tombstone 생성 & 실제 변수 가리킴
- 동적 변수 해제 → tombstone
nil설정 - 이후 pointer 로 접근 →tombstone 이
nil이면 해제
- 단점 : tombstone 유지 시간 & 공간 비용
- Locks-and-key Approach
- pointer 값을 (key, address) 쌍으로 표현. 동적 변수에 lock 값 함께 저장
- 동작 방식
- 동적 변수 할당 → lock 값 생성, pointer 의 key 에 같은 값 복사
- pointer 복사 → key 값도 함께 복사
- 역참조 → pointer 의 key 와 변수의 lock 비교, 일치 시 접근 허용
- 동적 변수 해제 → lock 값을 지움

- Tombstone Approch (묘비석 방식)
- Heap Management
- 가정 : Heap 은 고정 크기로 할당된 공간 & 사용 가능한 cell 은 linked list 로 연결되어 관리
- 해제가 암묵적으로 이루어지면 언제 수행?
- Reference Counter (참조 카운터) → 점진적 회수 (incremental reclamation)
- 구현 방법 : 모든 cell 에 카운터 두고, 현재 그 cell 을 가리키는 pointer 수 저장
- pointer 가 가리킴 → counter++
- pointer 가 떠남 → counter—
- counter 가 0이 됨 → memory 회수 - 단점
- counter 저장 공간 overhead
- counter 유지 실행 시간 overhead
- circular reference 문제 → 서로를 가리키는 두 객체는 counter 절대 0 XX

- Garbage Collection (가비지 컬렉션) → 일괄 회수 (batch reclamation)
- run-time 시스템이 memory 계속 할당. 모든 memory 소진 → 한꺼번에 garbage 수거!
- 모든 heap cell 에는 garbage 여부 표시 indicator bit (마크 비트) 있음
- 고정 크기 Garbage Collection
- heap 의 모든 cell 을 garbage 로 표시
- 프로그램의 모든 pointer 추적해 접근 가능한 cell 은 garbage X 표시
- 남은 garbage 들 사용 가능 공간 리스트로 변환
- 단점
- 메모리가 꽉 찼을 때 수행 → 필요할 때 가장 느리게 동작..
- 마크 비트 저장 공간 overhead
- 모든 pointer 추적 시간 overhead
- 가변 크기 Garbage Collection 추가 문제
- heap 의 모든 cell 을 garbage 로 초기 설정 어려움
- pointer 없는 cell 있어 마킹 과정 발생
- 회수 후 단편화 (fragmentation) 문제 → 사용 가능 공간 흩어짐
- Reference Counter (참조 카운터) → 점진적 회수 (incremental reclamation)
공유하기
Twitter Facebook LinkedIn글 이동
시리즈 이동
Comments