7. Basic Types(1)

하모씨·2021년 10월 15일
0

KNKsummary

목록 보기
4/23

1. Integer Types

C언어는 기본적으로 다른 종류인 두 가지 숫자 자료형을 지원하는데, 정수(integer) 자료형과 부동소수점(floating) 자료형이다. 정수 자료형의 값은 모든 숫자이고, 부동소수점 자료형의 값은 여기서 분수 부분을 가질 수 있다. 정수 자료형은 signed 또는 unsigned 2개로 분류된다.

만약 숫자가 0이거나 양수면 signed 정수의 가장 왼쪽 비트는 0이고, 음수면 1이다. 그래서 가장 큰 16bit 정수를 이진형태로 나타내면 아래와 같다.

0111111111111111 // 32767((2^15)-1)

정수가 sign bit가 아닐 때, 즉 맨 왼쪽 비트가 숫자의 규모를 나타내는 비트일때 이 정수를 unsigned라고 부른다. unsigned 정수의 가장 큰 16비트 값은 65535((2^16)-1)이다.
기본적으로 C언어에서 정수 변수들은 signed이다. 만약 컴파일러가 변수를 sign bit로 보지 않게하기 위해서 우리는 unsigned를 선언해주어야 한다.
unsigned 숫자는 주로 시스템 프로그래밍과 기계 의존적인 어플리케이션인 low-level에서 유용하다.

C언어의 정수 자료형은 다른 사이즈를 가진다. int 자료형은 보통 32bit이지만 오래된 CPU에서는 16bit일 수도 있다. 몇몇 프로그램들은 int형에 너무 큰 숫자를 요구하기 때문에 C언어는 long 자료형 또한 제공한다. 메모리를 보존할 필요가 있어 평소보다 더 작은 공간에 숫자를 저장하도록 하기 위해서는 short 정수형을 사용한다. 이런 명시자들을 심지어 섞어서 사용 할 수도 있다(ex. long unsigned int). 그렇지만 아래의 6개의 조합은 다른 자료형을 만들어낸다.


short int
unsigned short int

int
unsigned int

long int
unsigned long int

다른 명시자들의 조합은 위의 6개 자료형중 하나이다(long signed intlong int와 동일하다.). 명시자들의 순서는 상관이 없어서 unsigned short intshort unsigned int나 같다.
C언어는 단어 int를 제거하는 것으로 정수 자료형들의 이름의 약어를 허용한다. 예를 들어 unsigned short intunsigned short가 되거나, long intlong으로 된다. int를 생략하는 것은 C 프로그래머들 사이에서 흔하고, 새로운 C 기반 언어들도 short intlong int보다는 shortlong으로 사용한다.

6개의 정수 자료형이 나타내는 값의 범위는 기계마다 다르다. 하지만 모든 컴파일러들이 반드시 따라야할 규칙이 있다. 첫번째, C표준에서 short int, int, long int는 값의 특정한 최소 범위를 표현할 수 있어야 한다. 두번째, C표준에서 intshort int보다 짧으면 안되고, long intint보다 짧으면 안된다. 그러나 short intint와 동일한 값의 범위를 가지는 것은 가능하다. 또한 intlong int와 동일한 값의 범위를 가져도 된다.

/* 16 bit machine */
Type                Smallest Value        Largest Value

short int                  -32,768               32,767
unsigned short int               0               65,535
int                        -32,768               32,767
unsigned int                     0               65,535
long int            -2,147,483,648        2,147,483,647
unsigned long int                0        4,294,967,295

/* 32 bit machine */
Type                Smallest Value        Largest Value

short int                  -32,768               32,767
unsigned short int               0               65,535
int                 -2,147,483,648        2,147,483,647
unsigned int                     0        4,294,967,295
long int            -2,147,483,648        2,147,483,647
unsigned long int                0        4,294,967,295

/* 64 bit machine */
Type                            Smallest Value               Largest Value

short int                              -32,768                      32,767
unsigned short int                           0                      65,535
int                             -2,147,483,648               2,147,483,647
unsigned int                                 0               4,294,967,295
long int            -9,223,372,036,854,775,808   9,223,372,036,854,775,807
unsigned long int                            0  18,446,744,073,709,551,615

위의 표에서 나타나는 범위가 C표준에서 필수적인 것은 아니고, 컴파일러마다 다를 수 있다.
정수 자료형의 범위를 결정하는 방법 중 하나는 표준 라이브러리의 일부인<limits.h> 헤더에서 구현된 범위를 참조하여 결정하는 것이다. 이 헤더는 정수의 가장 큰 값과 가장 작은 값을 표현하는 매크로를 정의한다.

C99에서의 정수 자료형

C99는 두 가지 추가적인 자료형을 제공하는데, long long intunsigned long long int이다. 64비트 산수를 지원하기 위한 새로운 프로세서의 능력과 매우 큰 정수가 필요해지면서 이 자료형들이 추가되었다. long long 자료형은 최소 64비트만큼 넓어야 되는데, long long int의 값은 전형적으로 -(2^63)부터 (2^63) - 1 이고, unsigned long long int의 값은 보통 0에서 (2^64)-1이다.
short int, int, long int, long long int, signed char 자료형은 standard signed integer type이라고 부른다.
unsigned short int, unsigned int, unsigned long int, unsigned long long int, unsigned char, _Bool 자료형은 standard unsigned integer type이라고 부른다.
C99 표준은 implementation-defined로 signed와 unsigned에 대한 확장된 정수 자료형을 지원한다. 예를 들면 컴파일러는 signed, unsigned 128비트 정수 자료형을 제공할 수 있다.

정수형 상수(Integer Constants)

C언어는 정수형 상수로 10진수, 8진수, 16진수를 허용한다.

10진수(Decimal) 상수는 0~9로 이루어지고, 0으로 시작해서는 안된다.

15    255    32767

8진수(Octal) 상수는 0~7로 이루어지고, 0으로 시작해야 한다.

017    0377    077777

16진수(Hexadecimal) 상수는 0~9와 a~f로 이루어지고, 항상 0x로 시작해야 한다.

0xf    0xff    0x7fff

16진수 상수는 대문자나 소문자 둘다 사용해도 된다.

0xff    0xfF    0xFf    0xFF    0Xff    0XfF    0XFf    0XFF

8진수와 16진수는 숫자를 쓰는 다른 방법 그 이상이 아님을 명심해야 한다. 실제로 8진수와 16진수를 사용한다고 해서 실질적으로 숫자가 어떻게 저장되는지에는 영향을 미치지 않는다. 우리가 이것들을 어떻게 표현해도 정수들은 항상 2진으로 저장된다.
언제든 표현을 다른 것으로 바꿀 수 있고, 섞어서 써도 된다.

10 + 015 + 0x20

8진법과16진법은 low-level 프로그램을 작성하는 것에 편리하다.

10진수 상수의 자료형은 보통 int이다. 그러나 만약 상수가 int에 저장하기에는 너무 클 때에는 long int 자료형이 된다. long int에 저장하기에도 상수가 너무 크다면 최후의 수단으로 unsigned long int에 저장하도록 시도할 것이다. 8진수와 16진수 상수의 자료형을 결정하는 방법은 조금 다르다. 상수를 나타내기에 적합한 자료형을 찾을 때 까지 컴파일러는 int, unsigned int, long int, unsigned long int를 순서대로 확인해볼 것이다.
컴파일러가 상수를 long 정수로 취급하도록 강제하기 위해서는 단어 L 또는 l을 사용하면 된다.

15L    0377L    0x7fffL

상수가 unsigned라면 단어 U 또는 u를 사용하면 된다.

15U    0377U    0x7fffU

LU는 상수가 long이고 동시에 unsigned임을 나타내도록 조합하여 사용할 수 있다.
LU의 순서는 상관없다.

0xffffffffUL

C99에서의 정수형 상수(Integer Constants)

C99에서는 LLll을 붙여 상수가 long long int 자료형이 되도록 할 수 있다. LLllU를 붙이면 상수의 자료형이 unsigned long long int가 된다.

정수형 상수의 자료형을 결정하는 C99의 일반적인 규칙은 C89와 조금 다르다. 접미사(U, u, L, l, LL, ll)가 없는 10진 상수의 자료형은 해당하는 상수의 값을 나타낼 수 있는 int, unsigned int, long long int중 가장 작은 것이다. 그러나 8진, 16진 상수에 대해서는, int, unsigned int, long int, unsigned long int, long long int, unsigned long long int 순서로 가능한 자료형이다.

가능한 자료형의 종류에 따라 상수의 끝에 붙은 접미사는 달라진다. 예를 들면 U 또는 u로 끝나는 상수는 반드시 unsigned int, unsigned long int, unsigned long long int중 하나의 자료형을 가져야 한다. L 또는 l로 끝나는 10진 상수는 long intlong long int중 하나의 자료형을 가져야 한다. 만약 표준 정수 자료형 중 하나를 사용하기에 너무 큰 값이라면 상수는 더 확장된 정수 자료형이 된다.

정수 오버플로우(Integer Overflow)

산수 연산 정수에 수행되었을 때, 결과가 나타내기에는 너무 큰 숫자일 가능성이 있다. 예를 들어 산수 연산이 두 개의 int 값에 수행되었을 때, 결과는 반드시 int로써 나타나야 한다. 만약 값이 너무 많은 bit여서 int가 전부 표현할 수 없다면 우리는 이것을 overflow가 발생했다고 말한다.

정수 오버플로우가 발생했을 때 일어나는 행동은 피연산자가 signed인지 unsigned인지에 따라 다르다. signed 정수의 계산에서 오버플로우가 발생했다면 프로그램의 행동은 undefined이다. undefined behavior의 결과는 매우 다양하다. 계산의 결과가 단순히 잘못되거나, 프로그램이 crash를 일으키거나 다른 의도하지 않은 행동이 발생할 것이다.

그러나 만약 unsigned 정수의 계산에서 오버플로우가 발생했다면 프로그램의 결과는 defined이다. 우리는 올바른 정답인 모듈로(modulo) 2^n의 답을 얻을 것이다. n은 결과를 저장되는데 사용된 bit의 숫자이다. 예를 들어 unsigned인 16비트 숫자 65535에 1을 더했을 때, 결과는 0이 되는 것이 보장되어 있다((65535+1) % 2^16) = 0).

정수의 읽고 쓰기(Reading and Writing Integers)

int 변수의 overflow때문에 프로그램이 작동하고 있지 않다고 가정해보자. 그러면 첫번째 할 수 있는 생각으로는 intlong int로 바꾸는 것이다. 하지만 이것으로 끝나는 것이 아니고, 프로그램의 나머지 부분에 어떠한 영향을 미칠지 고려해야 한다. 특히, printfscanf의 호출에서 변수가 사용됐는지 확인해보아야 한다. 만약 그렇다면 %dint 자료형에만 작동하기 때문에 그 서식 문자열은 변경되어야 한다.

unsigned, short, long 정수를 읽고 쓰는 것은 몇몇의 새로운 변환 명시자(conversion specification)를 필요로 한다.

unsigned 정수를 읽고 쓸 때, 변환 명시자로 u, o, xd대신 사용해야 한다. u 명시자가 있다면, 그 숫자는 10진 표기로 읽거나 쓰인다. o는 8진 표기를, x는 16진 표기를 나타낸다.

unsigned int u;

scanf("%u", &u);	// reads  u in base 10
printf("%u", u);    // writes u in base 10
scanf("%o", &u);    // reads  u in base  8 
printf("%o", u);    // writes u in base  8
scanf("%x", &u);    // reads  u in base 16
printf("%x", u);    // writes u in base 16

short 정수를 읽고 쓸 때, hd, o, u, x 앞에 붙여야 한다.

short s;

scanf("%hd", &s);
printf("%hd", s);

long 정수를 읽고 쓸 때, ld, o, u, x 앞에 붙여야 한다.

long l;

scanf("%ld", &l);
printf("%ld", l);

long long 정수(C99에서만)를 읽고 쓸 때, lld, o, u, x 앞에 붙여야 한다.

long long ll;

scanf("%lld", &ll);
printf("%lld", ll);

2. Floating Types

정수 자료형이 모든 응용프로그램에서 적합한 것은 아니다. 때때로 우리는 소수점이 있는 숫자를 저장하는 변수를 사용해야 하거나, 아주 크고 아주 작은 숫자를 저장하는 변수를 사용할 필요가 있을 것이다. 이러한 숫자들 부동 소수점 서식(floating-point format)으로 저장된다.
C언어는 3가지 부동소수점 자료형을 제공한다.

float            Single-precision floating-point
double           Double-precision floating-point
long double      Extended-precision floating-point

float는 정확도가 그렇게 중요하지 않을때 적합하다(예를들면 온도는 소숫점 한자리수 까지만 계산함). double은 대부분의 프로그램에 충분할 정도로 좋은 정확도를 제공한다. long double은 궁극의 정확도를 제공하지만 거의 사용되지 않는다.
C 표준에서는 floatdoublelong double 자료형이 어느정도의 정확도를 제공하는지 설명하지는 않은데, 이는 다른 컴퓨터들이 부동소수점 숫자를 다른 방식으로 저장할 수도 있기 때문이다. 가장 현대의 컴퓨터들은 IEEE Standard 754(IEC 60559로도 알려진)의 명시를 따르고 있다.

IEEE Floating-Point Standard

IEEE Standard 754은 Institue of Electrical and Electronics Engineers에서 개발되었는데, 부동소숫점 숫자에 대해 두 가지 주요한 서식(format)을 제공한다. single precision(32bit)과 double precision(64bit)이다.
숫자는 과학적 표기법의 형태로 저장되고, 각각의 숫자들은 3가지 부분을 가지는데, sign, exponent, fraction이다. exponent에 저장된 비트의 수는 숫자가 얼마나 클지 또는 작을지 결정하고, fraction 내부의 비트의 수는 precision을 결정한다. single-precision 서식에서는 exponent가 8비트만큼이고, fraction은 23비트를 차지한다. 결과적으로 single-precision의 숫자는 대략적으로 (3.40 * (10^38))의 최대값을 가지고, 소숫점 여섯번째 자리까지의 정확도를 가진다.
IEEE standard는 또 다른 두가지 서식(format)을 서술하는데, single extended precision과 double extended precision이다. standard에서는 이 서식(format)들에 대한 비트의 숫자를 명시하지는 않지만, single extended type은 최소 43개의 비트를 차지해야하고, double extended type은 최소 79비트를 차지해야한다.

IEEE standard에 따르도록 구현된 floating 자료형의 특징은 아래와 같다(가장 작은 양수값은 일반화된 값이다. 일반적이지 않은 숫자는 더 작을 수 있다). long double 자료형은 아래에 있지 않은데, 그 이유는 길이가 기계마다 다양하기 때문이다. 보통 80비트나 128비트가 일반적인 사이즈이다.

Type        Smallest Positive Value        Largest Value        Precision
float          1.17549 * 10^(-38)         3.40282 * 10^38        6 digits
double         2.22507 * 10^(-308)        1.79769 * 10^308      15 digits

IEEE standard에 따르지 않는 컴퓨터라면, 위의 표는 유효하지 않다.
사실, 일부 컴퓨터에서는 floatdouble과 같은 값으로 취급되고, doublelong doulbe과 같은 값으로 취급될 수도 있다. <float.h> 헤더에서 부동소수점 자료형에 대한 특징을 정의하고 있는 매크로(macro)를 찾아볼 수 있다.
C99에서는 부동소수점 자료형이 두가지 카테고리로 나뉜다. float, double, long double 자료형은 하나의 카테고리인데, real floating type이라고 부른다. 부동소수점 자료형은 또 complex type을 포함하는데, float_Complex, double_Complex, long double_Complex가 C99에서 새롭게 추가되었다.

부동소수점 상수(Floating Constants)

부동소수점 상수는 다양한 방법으로 쓰일 수 있다. 예를 들어 아래의 상수들은 숫자 57.0을 쓴 다양한 유효한 방법이다.

57.0   57.   57.0e0   57E0  5.7e1   5.7e+1   .57e2   570.e-1

부동소수점은 반드시 소수점이나 지수를 포함해야한다. 지수는 숫자의 척도가 되는 10의 제곱의 형태로 나타난다. 만약 지수가 존재한다면, 반드시 단어 E 또는 e를 앞에 붙여야한다. +나 - 부호는 E 또는 e 뒤에 나타나야 한다.
기본적으로 부동소수점 상수는 double-precision 숫자로 저장된다. C 컴파일러가 57.0을 프로그램 안에서 발견했을 때, double 변수와 똑같은 서식(format)으로 메모리에 저장할 준비를 한다. 이 규칙은 일반적으로 문제를 일으키지 않는데, 필요할 경우에 자동적으로 double의 값이 float로 변환되기 때문이다.
가끔, float 또는 long double의 형식으로 부동소수점 상수를 저장하도록 컴파일러에게 강제해야할 필요가 있을 수 있다. single precision만 필요하다는 것을 나타내기 위해서는 상수의 끝에 단어 F 또는 f를 붙이면 된다(57.0F). 상수가 long double로 저장되도록 나타내고 싶으면 단어 L 또는 l을 끝에 붙이면 된다(57.0L).
C99는 부동소수점 상수를 16진수로 쓸 수 있는 방법을 제시하는데, 이런 상수는 0x0X로 시작한다(16진 정수 상수와 비슷하다). 이 특징은 거의 사용되지 않는다.

부동 소수점 숫자의 읽고 쓰기(Reading and Writing Floating-Point Numbers)

앞에서 논의한것 처럼, %e, %f, %g는 single-precision 부동소수점 숫자를 읽고 쓰는 것에 사용한다. doublelong double은 조금 다른 변환을 사용한다.

double의 값을 읽을 때 e, f, g 앞에 l을 붙인다.

double d;

scanf("%lf", &d);

lscanf 서식 문자열에만 사용하고, printf 문자열에는 사용하면 안된다. printf 서식 문자열에서는 e, f, g 변환 명시자들이 floatdouble에 둘다 사용 될 수 있다. (C99에서는 printf의 호출에 %le, %lf, %lg를 사용가능하도록 규정했지만 l은 아무 효과가 없다.)

long double의 값을 읽을 때 e, f, g 앞에 L을 붙인다.

long double ld;
scanf("%Lf", &ld);
printf("%LF", ld);

3. Character Types

char의 값은 컴퓨터마다 다양하게 나타날 수 있는데, 그 이유는 기계들이 서로 다른 문자 집합을 가질 수도 있기 때문이다.

문자 집합(character Sets)

오늘날 가장 유명한 문자 집합은 ASCII(American Standard Code for Information Interchange)이다. ASCII는 128 문자들을 표현할 수 있는 7비트 코드이다. ASCII에서는 숫자 0부터 9까지를 0110000-0111001로 표현하고, 대문자 A부터 Z까지는 1000001-1011010으로, 표현한다. 서부 유럽이나 많은 아프리카 언어에 필수적인 문자들을 제공하는 Latin-1로 ASCII를 종종 확장시키기도 한다.

char 자료형의 값은 어떠한 단일 문자든 할당 받을 수 있다.

char ch;

ch = 'a';
ch = 'A';
ch = '0';
ch = ' ';

큰따옴표가 아니라 작은따옴표로 문자 상수를 감싸는 것을 기억해야 한다.

문자에 대한 연산(Operations on Characters)

C언어에서 문자가 작동하는 것은 아주 간단한데, 하나의 사실 때문이다. C언어는 문자를 작은 정수로 처리한다. 결과적으로 문자들은 2진(binary)으로 인코드되고, 이 이진 코드를 정수로써 보는 것은 어렵지 않다. ASCII를 예로 들면, 0000000 부터 1111111까지의 범위를 가진 문자 코드들은 정수로 보면 0부터 127까지이다. 'a'는 97이고, 'A'는 65이고, '0'은 48이고, ' '은 32이다. 문자와 정수의 사이의 연결이 C에서는 아주 강하기 때문에, 문자 상수는 char 자료형보다 오히려 int 자료형을 가진다.
문자가 계산될 때, C언어는 그것의 정수 값을 이용한다. ASCII 문자 집합을 쓰는 아래의 예시를 보자.

char ch;
int i;

i = 'a';	// i is now 97
ch = 65;	// ch is now 'A'
ch = ch + 1;	// ch is now 'B'
ch++;		// ch is now 'C'

숫자가 비교가 가능하듯 문자도 비교가 가능하다. 아래의 if 구문은 ch가 소문자를 포함하는지 확인하고, 만약 그렇다면 ch를 대문자로 바꾸는 구문이다.

if ('a' <= ch && ch <= 'z')
    ch = ch - 'a' + 'A';

문자를 숫자로 바꾼 값은 문자 집합에 의존하기 때문에 문자를 비교하는 연산을 가진 프로그램은 포터블(portable)하지 못할 수 있다.
문자를 숫자로써 처리하는 것은 컴파일러에 의해 발견되지 않는 다양한 프로그래밍 오류를 발생시킬 수 있다. 프로그램은 내재된 문자 집합을 기반으로 하기 때문에 이동성(portability)의 족쇄가 될 수 있고, 'a' * 'b' / 'c'와 같은 의미 없는 표현식을 작성할 수도 있다.

Signed and Unsigned Characters

C언어는 문자를 정수로써 사용하기 때문에, char 자료형이 signed와 unsigned가 되는 것은 놀라운 일이 아니다.
signed 문자은 일반적으로 -128부터 127사이의 값을 가지고, unsigned 문자는 일반적으로 0부터 255사이의 값을 가진다.
C 표준은 일반적인 char가 signed인지 unsigned인지 따로 명시하고 있지는 않다. 어떠한 컴파일러는 이것을 signed 자료형이라고 처리하고, 또 어떠한 것은 unsigned 자료형이라고 처리한다.
대부분의 시간동안 우리는 char가 signed인지 unsigned인지 신경쓰지 않아도 된다.
그래도 어쩌다 가끔, 특히 우리가 문자 변수를 작은 정수를 저장하는 것에 사용하고 있다면 신경써야 될 때가 있다. 이러한 이유로 C언어는 char를 수정하는 것에 signedunsigned를 사용하는 것을 허용하고 있다.

signed char sch;
unsigned char uch;

이동성(portability)에 중점을 둔다면, char가 기본적으로 signed인지 unsigned인지 생각하지 말고, 만약 이게 문제가 된다면 signed charunsigned char를 사용하면 된다.

C89에서는 정수 자료형(integer types)과 문자 자료형 두쪽 모두를 정수의 자료형(integral types)이라는 용어를 써서 표현한다. 열거형(enumerated types) 또한 정수의 자료형(integeral types)이다.
C99는 "정수의 자료형(integral types)"라는 용어를 쓰지 않는다. 대신 "정수 자료형(integer types)"의 의미를 문자 자료형과 열거형까지 포함하도록 확장시켰다. C99의 _Bool 자료형도 unsigned 정수 자료형으로 다뤄진다.

Arithmetic Types

정수 자료형과 부동소수점 자료형은 통합적으로 arithmetic types으로도 알려져 있다.
C89에서의 arithmetic 자료형의 요약은 아래와 같다.

  • Integral types
    char
    signed integer types(signed char, short int, int, long int)
    Unsigned integer types(unsigned char, unsigned short int, unsigned int, unsigned long int)
    Enumerated types
  • Floating types(float,double, long double)

C99는 더 복잡한 계층을 가지고 있다.

  • Integer types
    char
    signed integer types, both standard(signed char, short int, int, long int, long long int) and extended
    unsigned integer types, both standard(unsigned char, unsigned short int, unsigned int, unsigned long int, unsigned long long int, _Bool) and extended
    Enumerated types
  • Floating types
    real floating types(float, double, long double)
    Complex types(float _Complex, double _Complex, long double _Complex)

Escape Sequences

문자 상수는 일반적으로 작은 따옴표로 묶여 있는 한 글자이다. 하지만 이 방식으로 쓰이지 않는 특별한 문자가 있다. 이것들은 보이지 않고(출력되지 않고) 키보드로부터 입력될 수 없다. 프로그램이 모든 기본 문자 집합을 처리할 수 있도록, C언어는 escape sequence를 제공한다.
escape sequence는 character escapes와 numeric escapes 두 종류가 있다.

Name		Escape Sequence
Alert(bell)		\a
Backspace		\b
Form feed		\f
New line		\n
Carriage return		\r
Horizontal tab		\t
Vertical tab		\v
Backslash		\\
Question mark		\?
Single quote		\'
Double quote		\"

\a, \b, \f, \r, \t, \v escape는 일반적인 ASCII 제어 문자들이다. \n escape는 ASCII line-feed 문자이다. \\ escape는 문자 상수나 문자열이 \ 문자를 포함할 수 있도록 해준다. \'\"는 '문자와 "문자를 포함할 수 있도록 해준다. \? escape는 거의 사용되지 않는다.
character escape는 편리하지만 문제가 있다. 출력되지 않는 모든 ASCII 문자들을 포함하지 않는다. character escape는 기본 128 ASCII 문자를 넘어가는 문자들에 대해서는 쓸모가 없다.
numeric escape는 어떠한 문자라도 표현 가능하기 때문에 이 문제를 해결할 수 있다.
numeric escape를 작성하기 위해서는, 테이블에서 문자의 8진이나 16진 값을 찾아야 한다. 예를 들어 ASCII escape(ESC) 문자는 33의 8진값을 가지고, 1B의 16진 값을 가진다.
이 코드들은 escape sequence로 쓰여 사용될 수 있다.

  • 8진 escape sequence는 \ 문자와 최대 3자리 8진 숫자로 이루어진다. 이 숫자는 반드시 unsigned 문자를 표현할 수 있어야 하며, 그렇기에 최대값은 보통 8진수 377이다. 예를 들어 escape sequences는 \33 또는 \033으로 쓰여야 한다. 8진 상수와는 다르게 escape sequence로 된 8진 숫자는 0으로 시작할 필요는 없다.
  • 16진 escape sequence는 \x와 16진 숫자로 이루어진다. C언어가 16진 숫자의 자리수에 제한을 두지 않는다고 하더라도, 반드시 unsigned 문자를 표현할 수 있어야 한다.(그래서 만약 문자가 8bit만큼 길다면 FF를 초과할 수 없다.) 이 표기를 사용하면, escape character는 \x1b 또는 \x1B로 쓸 수 있다. x는 반드시 소문자여야 하지만, 16진수 자리는(b같은) 대문자 소문자 둘 다 쓸 수 있다.

문자 상수로써 사용되었을 때, escape sequence는 반드시 작은 따옴표로 둘러싸여야 한다. 예를 들면, escape character를 표현하는 상수는 '\33' (또는 '\x1b')로 쓰여야 한다. escape sequence는 숨겨지는 경향이 있어서, #define을 통해 이름을 부여하는 것은 좋은 생각이다.

#define ESC '\33'

escape sequence가 문자를 나타내는데 있어서 유일하게 특별한 표기는 아니다. trigraph sequence도 문자 #, [, \, ], ^, {, |, }, ~와 같은 몇몇 도시의 키보드에서 입력할 수 없는 문자들을 나타내는 방법을 제공한다.
C99에서는 escape sequence와 비슷한 universal character names를 추가하였다. 그러나 escape sequence와는 다르게 universal character names는 식별자(identifiers)에서도 허용된다.

Character-Handling Functions

if ('a' <= ch && ch <= 'z')
    ch = ch - 'a' + 'A';

초반에 나왔던 이 if구문은 가장 좋은 방법이 아니다. 더 빠르고 더 이동성좋은(portable)한 방법은 C언어의 toupper 표준 라이브러리 함수를 사용하는 것이다.

ch = toupper(ch);    // converts ch to upper case */

toupper가 호출되면, toupper는 매개변수가 소문자인지 체크한다. 만약 그렇다면, toupper는 대응하는 대문자를 반환한다. 만약 그렇지 않다면 toupper는 매개변수의 값을 반환한다.
toupper의 호출은 #include 지시자에 이은 <ctype.h> 헤더가 필요하다.

scanfprintf를 사용한 문자의 읽고 쓰기

%c 변환 명시자는 scanfprintf가 한 글자를 읽게하는 것을 가능하게 해준다.

char ch;

scanf("%c", &ch);	// reads a single character
printf("%c", ch); 	// writes a single character

scanf는 한 문자를 읽기 전까지 white-space character를 스킵하지 않는다. 만약 다음 읽히지 않은 문자가 스페이스라면, 변수 ch에는 스페이스가 포함된 채로 scanf가 반환될 것이다. scanf가 한 문자를 읽기 전에 공백을 스킵하도록 하려면 %c의 앞에 스페이스를 넣어주면 된다. scanf 서식 문자열의 안에 있는 공백은 "0을 스킵하거나, 공백 문자를 스킵하라"는 의미이기 때문이다.

scanf(" %c", &ch);

scanf는 일반적으로 공백을 스킵하지 않기 때문에 방금 읽은 문자가 개행 문자인지 확인하여 입력 라인의 끝을 찾아내기가 쉽다. 아래의 예시는 현재 입력 라인에서 모든 남은 문자를 읽고 무시하는 예시이다.

do
{
    scanf("%c", &ch);
} while(ch != '\n');

getcharputchar를 사용한 문자의 읽고 쓰기

C언어는 하나의 문자를 읽고 쓰는 다른 방법을 제공한다. 특히, 우리가 getcharputchar 함수를 scanfprintf의 호출 대신에 사용할 수 있다.

putchar은 한 글자를 쓴다(write) .

putchar(ch);

getchar 함수가 호출될 때마다, 한 문자를 읽고, 그것을 반환한다. 이 문자를 저장하기 위해서는 변수에 저장하기 위해 대입을 사용해야 한다.

ch = getchar();

getcharchar값이 아닌 int 값을 실질적으로 반환한다. 결과적으로 getchar로 문자를 읽어서 저장할 했을 때 char보다는 int 자료형을 가지는 것이 일반적이다.
scanf처럼 getchar도 공백 문자를 스킵하지 않고 읽는다.
getcharputchar를 사용하는 것은 scanfprintf를 사용하는 것보다 프로그램이 실행되었을 때 시간을 더 절약할 수 있다. getcharputchar는 두 가지 이유로 빠르다. 첫번째로는 다양한 서식(format)의 많은 데이터를 읽는 scanfprintf보다 더 간단하다. 두번째로는 getcharputchar는 추가적인 속도를 위해 매크로(macro)로써 구현이 되어있는 것이 일반적이다.
getcharscanf를 넘어서는 또다른 장점을 가진다. 왜냐하면 getchar는 자기가 읽은 문자를 반환하는 특징이 있고, 또 getchar는 다양한 C 관용구에 자기 자신을 빌려줄 수 있기 때문이다. 아래의 예시를 보자.
입력 라인의 나머지 부분을 스킵하는 scanf 루프의 예시이다.

do
{
    scanf("%c", &ch);
} while(ch != '\n');

getchar를 사용해보자.

do
{
    ch = getchar();
} while(ch != '\n');

getchar를 controlling expression에 넣어 루프를 더 압축시킬 수 있다.

while((ch = getchar()) != '\n');

사실 ch도 필요가 없다. 왜냐하면 getchar의 반환값이 읽은 문자이기 때문에 바로 표현식에 사용할 수 있기 때문이다.

while(getchar() != '\n');

getcharscanf를 같은 프로그램에 사용할 때 주의해야 한다. scanfscanf가 발견했지만 읽지 않은 문자들을 남기는 경향이 있다.

printf("Enter an integer: ");
scanf("%d", &i);
printf("Enter a command: ");
command = getchar();

위의 사례를 보자. i에 정수의 값을 입력하기 위해 정수를 키보드로 입력하고 엔터를 누르는 순간 \n가 발생한다. 하지만 scanf의 특성상 %d에 맞는 문자인 정수만 입력을 받은 뒤, \ni에 저장되지 않고 남게 된다. 그리고 getchar() 함수가 호출되면 남아있던 \ncommand에 저장될 것이다. 비단 개행문자만 포함되는 것이 아니다. 12345d를 입력했다고 가정하면, i에는 12345가 저장될 것이고, command에는 d가 저장될 것이다.

profile
저장용

0개의 댓글