프로그래밍언어론 9강 - 타입의 분류와 단순 타입
타입을 데이터 집합과 연산 집합의 결합으로 이해하고, 타입 안전성에 따라 프로그래밍 언어를 구분한다. 원시·사용자 정의 타입과 단순·복합 타입의 차이를 정리한 뒤 정수형, 실수형, 문자형, 논리형, 열거형의 데이터 표현과 허용 연산을 학습한다.
제1장 타입과 타입 안전성
1. 타입의 정의
타입(type)은 데이터 집합과 그 데이터에 적용할 수 있는 연산 집합의 결합이다. 정수형을 예로 들면 데이터 집합은 0, 양의 정수, 음의 정수 가운데 컴퓨터가 표현할 수 있는 값들로 이루어지고, 연산 집합에는 덧셈·뺄셈·곱셈·나눗셈·나머지 연산 등이 포함된다. 타입은 단순히 값의 저장 형식만 뜻하지 않고, 그 값을 어떤 방식으로 처리해도 되는지까지 규정한다.
타입은 변수의 주요 속성 가운데 하나이다. 변수에는 그 타입이 지원하는 데이터만 저장하고 허용된 연산만 적용해야 한다. 타입은 서브프로그램의 인수와 반환값에도 사용된다. 예를 들어 int swap(int x, int y)라는 선언은 인수와 반환값이 정수형임을 나타내며, 호출 전후에 이 약속이 지켜져야 정확한 연산 결과를 기대할 수 있다.
핵심: 타입은 ‘어떤 값인가’와 ‘어떤 연산이 가능한가’를 함께 정의한다. 같은 비트열도 타입에 따라 값의 해석과 적용할 수 있는 연산이 달라질 수 있다.
2. 타입 안전성
타입 안전성(type safety)은 프로그램의 모든 연산과 함수 적용에서 입력과 출력의 타입 관계가 일관되게 유지되는 성질이다. 함수 f의 타입이 f(x): A → B라면, 모든 a ∈ A에 대해 f(a) ∈ B가 되어야 한다. 즉 정의역에 속하는 올바른 인수를 적용했을 때 결과도 약속된 공역의 타입에 속해야 한다.
연산 또는 서브프로그램을 적용하기 전후의 타입이 일치하면 잘못된 데이터 해석을 방지하고 정확한 연산 결과를 보장하는 데 도움이 된다. 프로그램의 모든 연산과 함수가 이 성질을 만족하여 타입 오류가 발생하지 않는다면 그 프로그램은 타입 안전하다고 말한다.
3. 타입 안전성에 따른 언어 분류
| 구분 | 특징 | 강의의 예 |
|---|---|---|
| 강타입 언어 | 모든 타입 오류를 검출함 | Haskell, ML, Java(타입 캐스팅 제외) |
| 약타입 언어 | 타입 오류를 검출하지만 일부 타입 오류를 허용함 | C의 공용체와 타입 캐스팅 |
| 무타입 언어 | 타입 선언문이 없고 대상의 타입이 계속 바뀔 수 있음 | Python 등 다수의 스크립트 언어 |
강타입 언어(strongly typed language)는 타입 규칙 위반을 모두 검출한다. 약타입 언어(weakly typed language)도 타입 오류를 검사하지만 특정 기능을 이용하면 검사를 피하거나 일부 오류를 허용할 수 있다. C에서는 공용체나 타입 캐스팅을 통해 타입 검사를 우회할 수 있다. 무타입 언어(typeless language)는 타입 선언문이 없고 한 대상의 타입이 계속 바뀔 수 있는 언어를 가리킨다.
이 분류는 강의에서 제시한 타입 안전성 관점의 분류이다. 강타입·약타입·무타입을 컴파일 언어·인터프리터 언어와 단순히 같은 구분으로 보아서는 안 된다.
제2장 타입의 여러 분류 기준
1. 데이터 형태에 따른 분류
가장 익숙한 분류는 데이터의 형태에 따라 정수형, 실수형, 문자형, 배열, 구조체 등으로 나누는 것이다. 이 분류는 어떤 데이터를 표현하는가에 초점을 둔다. 그러나 타입은 언어가 기본 제공했는지, 한 값이 하나의 데이터인지 구조화된 여러 데이터인지에 따라서도 분류할 수 있다.
2. 원시 타입과 사용자 정의 타입
원시 타입(primitive type)은 프로그래밍 언어가 기본적으로 제공하는 타입으로, 미리 정의된 타입 또는 내장 타입이라고도 한다. 대부분의 언어는 정수형, 실수형, 문자형, 논리형을 기본 제공한다. 강의에서는 C와 C++의 int, float, char, 배열과 Java의 int, float, char, boolean, 배열 등을 예로 든다.
사용자 정의 타입(user-defined type)은 사용자가 필요한 데이터 구조를 직접 정의해 사용하는 타입이다. 배열은 크기와 데이터 종류를 지정하고, 구조체는 구성 데이터의 종류를 지정한다. C에서는 enum, struct, union, C++와 Java에서는 enum, class 등이 대표 예이다.
배열처럼 어떤 언어에서는 기본 제공 요소로 보면서도 사용자가 크기와 원소 타입을 정해 구체화하는 타입이 있을 수 있다. 따라서 원시·사용자 정의 구분은 언어의 제공 방식과 사용자의 타입 정의 개입 여부를 기준으로 판단해야 한다.
3. 단순 타입과 복합 타입
단순 타입(simple type)은 데이터 집합의 각 요소가 하나의 데이터로만 구성된 타입이다. 스칼라 타입 또는 원자 타입이라고도 하며 정수형, 실수형, 문자형, 논리형, 열거형 등이 해당한다. C++의 int, float, char, bool, enum이 예이다.
복합 타입(composite type)은 데이터 집합의 각 요소가 여러 데이터의 구조로 이루어진 타입이다. 단순 타입이나 다른 복합 타입을 재료로 요소를 구성하므로 구조 타입이라고도 한다. 배열, 구조체, 클래스가 대표적이며 C의 배열·struct·union, C++와 Java의 배열·class가 예이다.
| 분류 기준 | 첫 번째 범주 | 두 번째 범주 |
|---|---|---|
| 타입 정의에 사용자가 개입하는가 | 원시 타입: 언어가 기본 제공 | 사용자 정의 타입: 사용자가 직접 정의 |
| 데이터 요소가 어떤 형태인가 | 단순 타입: 하나의 데이터 | 복합 타입: 데이터들의 구조 |
시험 포인트: 원시·사용자 정의는 ‘누가 타입을 정의하는가’의 구분이고, 단순·복합은 ‘데이터 요소가 하나인가 구조인가’의 구분이다. 두 분류 기준을 서로 바꾸어 설명하지 않아야 한다.
제3장 정수형과 실수형
1. 정수형의 데이터 집합
정수형(integer type)은 정수 데이터를 다루는 단순 타입이다. 수학의 정수 집합은 무한하지만 컴퓨터의 메모리는 유한하므로 전체 정수 가운데 일부만 표현한다. 표현 가능한 범위는 할당된 비트 수와 부호 표현 여부에 의존한다.
C와 C++은 short, int, long, long long과 각각의 unsigned 형태를 제공한다. 강의 표에서 최소 사용 비트는 short와 int가 16비트, long이 32비트, long long이 64비트이다. n비트의 부호 있는 정수 범위는 -2^(n-1)부터 2^(n-1)-1까지이고, 부호 없는 정수 범위는 0부터 2^n-1까지이다.
Java의 정수형은 사용 비트가 고정된다. byte는 8비트, short는 16비트, int는 32비트, long은 64비트이며, C/C++과 달리 unsigned가 붙는 정수형이 없다.
| Java 타입 | 사용 비트 | 데이터 범위 |
|---|---|---|
| byte | 8 | -2^7 ~ 2^7-1 |
| short | 16 | -2^15 ~ 2^15-1 |
| int | 32 | -2^31 ~ 2^31-1 |
| long | 64 | -2^63 ~ 2^63-1 |
2. 정수형의 연산
정수형에는 덧셈, 뺄셈, 곱셈, 나눗셈의 사칙연산을 적용할 수 있다. 정수형 연산 결과는 해당 타입의 표현 범위 안의 정수로 다루어진다. 강의의 16비트 short 예에서는 최댓값 32767에 1을 더하면 최솟값 -32768로, 최솟값 -32768에서 1을 빼면 최댓값 32767로 돌아오는 현상을 보여 준다.
나머지 연산은 Pascal의 mod, C·C++·Java의 %로 나타낸다. 예를 들어 9 % 5는 4이다. <, >, <=, >=, ==, != 같은 관계 연산의 결과는 논리형이고, ^, &, | 같은 비트 연산도 사용할 수 있다.
3. 실수형과 근사 표현
실수형(real type)은 실수 데이터를 다루는 단순 타입이다. 전체 실수는 무한하며 연속적이므로 유한한 비트로 모두 정확히 표현할 수 없다. 실수형은 사용 비트 수에 따라 일부 범위와 정밀도만 제공하고, 실수 데이터는 일반적으로 근사값으로 저장된다.
실수는 보통 부동소수점 수(floating-point number)로 표현한다. 전체 비트는 부호, 지수부, 가수부로 나뉜다. 부호는 양수일 때 0, 음수일 때 1이다. 실수를 1.xxxx × 2^지수 형태로 정규화한 뒤, 지수부에는 실제 지수에 bias를 더한 값을 저장하고 가수부에는 정규화 후 소수점 아래 부분만 저장한다.
지수부가 m비트이면 강의에서 bias를 2^(m-1)-1로 계산한다. 예를 들어 +5.0의 이진 표현 101.0은 1.01 × 2^2로 정규화된다. 지수부가 3비트라 bias가 3이면 지수부에는 2+3=5가 저장되고, 가수부에는 선두의 1과 소수점을 제외한 01 이후 부분을 저장한다.
4. float와 double
C, C++, Java에서 float는 32비트로 부호 1비트, 지수부 8비트, 가수부 23비트를 사용하며 bias는 127이다. double은 64비트로 부호 1비트, 지수부 11비트, 가수부 52비트를 사용하며 bias는 1023이다. 비트 수가 많은 double이 일반적으로 더 넓은 범위와 더 높은 정밀도를 제공한다.
| 타입 | 전체 비트 | 부호·지수부·가수부 | bias |
|---|---|---|---|
| float | 32 | 1·8·23비트 | 127 |
| double | 64 | 1·11·52비트 | 1023 |
실수형에도 사칙연산과 관계 연산을 적용한다. 사칙연산 결과는 실수형이며 표현할 수 있는 최댓값이나 최솟값 범위를 넘으면 양의 무한대 inf 또는 음의 무한대 -inf로 표현될 수 있다. 관계 연산의 결과는 논리형이다.
정수형은 유한 범위의 정수를 이산적으로 표현하고, 실수형은 부동소수점 구조로 실수를 근사 표현한다. 실수형에서 비트 수가 늘어나면 범위와 정밀도는 커지지만, 모든 실수를 정확히 저장하게 되는 것은 아니다.
제4장 문자형·논리형·열거형
1. 문자형
문자형(character type)은 하나의 문자 데이터를 다룬다. 데이터 집합은 사용하는 문자 코드 체계에서 표현할 수 있는 문자들이다. ASCII는 특수 기호, 구두점, 숫자, 영어 대소문자 등 128개의 문자로 구성된다. C와 C++의 char는 8비트이며, 유니코드는 세계의 다양한 문자를 표현한다. Java의 char는 16비트이다.
문자형에는 관계 연산을 적용할 수 있고 결과는 논리형이다. 문자 코드 순서에 따라 'A' < 'B'는 참이다. C와 C++에서는 char를 8비트 정수형으로 간주하므로 사칙연산과 비트 연산도 가능하다. ASCII에서 'A'의 코드 65에 32를 더하면 97인 'a'가 되고, 'a'에서 32를 빼면 'A'가 된다.
2. 논리형
논리형(logical type)은 참과 거짓을 다루는 타입이다. C의 _Bool은 데이터 집합 {1,0}, C++의 bool과 Java의 boolean은 {true,false}를 사용한다. 논리곱 AND, 논리합 OR, 논리부정 NOT 등을 적용하며 결과도 논리형이다. 예를 들어 true && false는 false이다.
3. 열거형
열거형(enumeration type)은 순서 관계가 있는 이름들을 데이터로 다루는 단순 타입이다. 데이터 집합은 사용자가 직접 지정한 이름들로 이루어지며 각 이름은 0 이상의 정수와 대응하므로 이름 사이의 순서 관계가 성립한다.
C와 C++의 enum에서는 값을 지정하지 않으면 첫 이름이 0부터 시작해 순서대로 정수와 대응한다. enum Year { Jan, Feb, Mar, ... };에서 Jan은 0, Feb는 1의 방식으로 대응한다. 사용자가 특정 이름의 정수를 직접 지정할 수도 있고, 이후 지정하지 않은 이름은 앞의 값 다음 정수와 대응한다.
예를 들어 Jan=1, Feb, Mar, Apr=10, May=15, Jun=1, Jul, Aug처럼 일부 값을 직접 지정하면 Jan, Feb, Mar는 각각 1, 2, 3이고 Jun, Jul, Aug도 각각 1, 2, 3이 된다. 정수값이 중복되어도 선언 순서에 따른 이름의 순서 관계는 유지된다.
열거형에는 관계 연산을 적용하며 결과는 논리형이다. C에서는 대응된 정수값을 기반으로 사칙연산도 가능하다. 강의 예제는 월 이름을 Jan부터 Dec까지 반복하면서 대응 정수 0부터 11까지 출력한다.
단순 타입 비교: 정수형은 제한된 정수, 실수형은 부동소수점 근삿값, 문자형은 문자 코드의 한 문자, 논리형은 참과 거짓, 열거형은 정수와 대응되는 순서 있는 이름을 다룬다. 각 타입은 데이터 집합뿐 아니라 적용 가능한 연산도 함께 기억해야 한다.
핵심 개념 정리
타입은 데이터 집합과 연산 집합의 결합이며 변수, 서브프로그램의 인수와 반환값을 제한해 올바른 연산을 돕는다. 모든 연산과 함수에서 타입 관계가 지켜져 오류가 발생하지 않는 성질이 타입 안전성이다.
타입은 사용자 개입 여부에 따라 원시 타입과 사용자 정의 타입으로, 데이터 요소의 구조에 따라 단순 타입과 복합 타입으로 나뉜다. 단순 타입에는 정수형, 실수형, 문자형, 논리형, 열거형이 있다.
정수형의 범위는 비트 수와 부호 여부에 좌우되고, 실수형은 부호·지수부·가수부로 이루어진 부동소수점 수로 근사 표현된다. 문자형은 문자 코드 체계를 사용하고, 논리형은 참과 거짓을 다루며, 열거형은 정수와 대응되는 순서 있는 이름을 데이터로 다룬다.
최종 정리: 타입 문제는 언제나 데이터 집합과 연산 집합을 함께 살펴야 한다. 분류 기준을 구별하고, 각 단순 타입의 표현 범위·메모리 구조·연산 결과 타입을 연결하면 타입 안전성과 언어별 차이를 정확히 판단할 수 있다.
예상문제 20선
1. 타입의 정의로 가장 적절한 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ④
타입은 어떤 값을 다루는지뿐 아니라 그 값에 어떤 연산을 허용하는지까지 함께 정의한다.
2. 함수 f(x): A → B가 타입 안전하기 위한 조건은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ②
정의역 A의 올바른 입력에 함수를 적용한 결과가 약속된 공역 B의 타입에 속해야 타입 관계가 유지된다.
3. 타입 안전성에 따른 언어 분류의 설명으로 옳은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ①
강의에서는 모든 타입 오류를 검출하는 언어를 강타입 언어로 분류한다. 약타입 언어는 일부 오류를 허용한다.
4. 타입 정의에 사용자가 개입하는지에 따른 분류는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ③
언어가 기본 제공하면 원시 타입, 사용자가 직접 정의하면 사용자 정의 타입이다.
5. 복합 타입에 대한 설명으로 옳은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ②
복합 타입은 여러 데이터로 이루어진 구조를 한 요소로 다루며 배열, 구조체, 클래스가 대표 예이다.
6. 다음 중 단순 타입이 아닌 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ④
구조체는 여러 데이터로 구성되는 복합 타입이다. 정수형, 논리형, 열거형은 하나의 데이터를 요소로 하는 단순 타입이다.
7. n비트 부호 없는 정수형이 표현하는 범위는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ③
부호 비트가 따로 필요 없는 n비트 unsigned 정수는 0부터 2^n-1까지 표현한다.
8. Java 정수형에 대한 설명으로 옳은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ①
Java 정수형은 각 타입의 사용 비트가 고정되어 있으며 C/C++과 달리 unsigned가 붙는 정수형이 없다.
9. 정수형 관계 연산의 결과 타입은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ③
<, >, == 같은 관계 연산은 두 값을 비교해 참 또는 거짓을 반환하므로 결과가 논리형이다.
10. C 계열의 나머지 연산 9 % 5의 결과는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ②
9를 5로 나누면 몫은 1이고 나머지는 4이므로 9 % 5는 4이다.
11. 실수형 데이터 표현에 대한 설명으로 옳지 않은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ④
실수 집합은 무한하고 연속적이므로 유한한 비트로 모두 정확히 표현할 수 없다. 부동소수점 수는 근사 표현이다.
12. 부동소수점 수의 기본 구성 요소를 모두 바르게 나열한 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ①
부동소수점 수는 수의 부호, 크기 범위를 정하는 지수부, 유효 숫자를 담는 가수부로 나뉜다.
13. 지수부가 m비트일 때 강의에서 제시한 bias 계산식은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ②
강의는 지수부가 m비트일 때 bias를 2^(m-1)-1로 정의한다. 지수부에는 실제 지수와 bias의 합을 저장한다.
14. float와 double의 구조 비교로 옳은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ③
float는 총 32비트, double은 총 64비트이며 double이 더 큰 지수부와 가수부를 사용한다.
15. 문자형에 대한 설명으로 옳은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ①
문자형은 ASCII나 유니코드 같은 문자 코드 체계가 제공하는 문자를 데이터로 다룬다.
16. C/C++에서 ASCII 코드에 따라 'A' + 32의 결과에 해당하는 문자는?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ④
ASCII에서 'A'는 65이고 'a'는 97이다. C/C++의 char를 정수형처럼 계산하면 65+32는 97이 된다.
17. 논리형의 데이터와 연산에 관한 설명으로 옳은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ①
논리형은 참과 거짓을 다루며 논리 연산 결과 역시 참 또는 거짓의 논리형이다.
18. 열거형에 대한 설명으로 옳지 않은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ③
열거형 이름들은 정수와 대응하므로 순서 관계가 성립한다. 이것이 열거형의 핵심 특징이다.
19. enum Year { Jan, Feb, Mar };에서 값을 따로 지정하지 않았을 때 일반적인 대응은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ④
C/C++의 enum에서 값을 지정하지 않으면 첫 이름이 0이고 이후 이름이 1씩 증가하는 정수와 대응한다.
20. 각 단순 타입과 핵심 표현의 연결로 알맞은 것은?
정답입니다.
오답입니다. 답안을 다시 선택해 보세요.
정답 및 해설 보기
정답: ②
실수형은 부동소수점 구조로 근사값을 저장한다. 정수형, 문자형, 논리형, 열거형은 각각 다른 데이터 집합과 연산을 갖는다.
댓글
댓글 쓰기