C는 기본적으로 수와 관련하여 두 가지 자료형을 지원한다. 하나는 정수형이고, 하나는 소수형이다. 여기서 정수형은 모든 정수를 말하는 것이고, 소수형은 여기서 소수점 이하부분도 가지게 된다.
유부호와 무부호형 정수
정수형 자료를 이진수로 나타냈을때, 부호형 정수는 가장 왼쪽의 비트를 부호를 나타내는 용도로 사용된다. 만약 그 비트가 1이라면 해당 자료는 음수다. 그러나 무부호형 정수의 경우 그 부분도 수를 나타내는데 사용하므로, 나타낼 수 있는 수의 갯수는 같으나 표현할 수 있는 가장 큰 값은 더 커진다.
사실 정수형 자료들은 각기 다른 크기를 가지고 있다. 이 크기는 정해져 있지 않다. 이것은 컴퓨터의 사양에 따라 달라질 수 있다. 다만 short int, int, long int, long long int의 순으로 자료형의 크기가 이뤄졌다는 규칙은 절대적이다.(인접한 자료형의 크기가 서로 같을 수는 있다.) 참고로 int를 제외한 나머지에서 int를 생략해서 표현해도 괜찮다.
64비트 CPU를 기준으로 각각 16비트 / 32비트 / 64비트 / 128비트 다.
읽고, 쓰이고, 계산되는 숫자가 아닌, 프로그램의 문자로 나타나는 상수에 대해서 알아보자. C는 정수형 상수가 10진법 외에 8진법, 16진법으로 쓰일 수 있게 한다.
이 때 8진법은 숫자 앞에 0을 집어넣어서 표현하면 된다. 16진법의 경우, 0x다.
만약 10진법 정수형 상수가 int의 크기를 벗어난다면 컴파일러는 long int, unsigned long int 순으로 크기를 정할 것이다. 그러나 8진법 16진법의 경우 unsigned int 가 추가되어서 고려된다.
컴파일러에게 상수를 long 로 다루도록 지시하기 위해서 다음과 같이 L 혹은 l을 뒤에 넣을 수 있다. 물론 무부호형을 나타내기 위해 U 혹은 u을 같이 활용할 수 있다.
15U, 0377L, 0xffffffffUL
C99의 경우 C89와는 달리 십진법상에서 상수의 크기를 정의하는 방식이 살짝다른데, 무부호형을 고려하지 않는 것만 기억하자. 만약 접미사로 l, u가 붙어있다면 고려하는 경우의 수는 더 적어질 것이다.
만약 주어진 자료가 크기를 벗어난다면 어떻게 될까? 양수 범위에서 크기를 벗어난다면 다시 0으로 돌아가는 것은 확실하다. 하지만 음수범위에서 크기를 벗어난다면 어떤 결과가 나올지는 보장할 수 없다.
여기서는 정수형에 쓰일 수 있는 변환 규격들을 살펴볼 것이다.
unsigned int > u
int > d
8진법 > o
16진법 > x
short > h : d, o, u, x 앞에 붙여쓸 수 있다.
long > l : 상동
long long > ll : 상동
일반적으로 float는 소수점 이하 6자리까지, double은 15자리까지 정확하다. 물론 이것은 대략적인 수치다. 이는 IEEE(Institute of Electrical and Electronics Engineers) 표준 754에 따른 것으로, 이 표준을 따르지 않는 컴퓨터에서는 다른 정확성을 보여 줄 수 있다.
다음과 같은 방식으로 나타낼 수 있다. 아래의 표현들은 전부 같은 수를 나타내고 있다.
57.0 57. 57.0e0 57E0 5.7e1 5.7e+1 .57e2 570.e-1
기본적으로 C 컴파일러는 소수가 주어질 경우 double 변수와 같은 크기로 저장한다. 이는 크게 문제가 되지 않는데, double로 저장되었더라도 필요한 경우에 자동적으로 float으로 변환되기 때문이다.
그럼에도 불구하고 float과 같은크기로 저장하고 싶다면 숫자 뒤에 F 혹은 f 접미사를 붙여주도록 하자. 반대로 long double로 저장하고 싶다면 L 혹은 ㅣ 만 붙여주도록 하자.
앞에서 살펴봤듯이 소수와 관련된 변환규격자들에는 e, f, g가 있다. 만약 double로 읽고 싶다면 l앞에 붙여주면 된다. 이는 scanf에만 해당되는 방법으로 printf에서는 사용할 수 없다. printf에서 e, f, g는 float와 double 둘 모두를 지원하기 때문이다. C99에서 l을 사용할 수 있게 해주었지만 의미없다.
만약 long double을 읽고 쓰는 경우에는 L 을 써주자.
현재 남아있는 기본 자료형은 char뿐이다. 이 자료형의 값은 컴퓨터마다 다를 수 있다. 왜냐하면 기기마다 서로 다른 문자 세트를 가지고 있을 수 있기 때문이다. 물론 오늘날에 이르러 가장 유명한 문자 세트는 아스키(ASCII, American Standard Code for Information Interchange)다. 7비트로 이뤄져 있다.
7비트로 이뤄진 정수에 대응하는 문자가 있다는 것은 문자끼리 연산이 가능하다는 뜻이다. 즉 C는 char을 정수형 자료처럼 다룬다. 그럼 여기서 의문이 들 것이다. char 자료형은 무부호형으로 다뤄질 것인가? 유부호형으로 다뤄질 것인가? 이는 컴파일러마다 달라질 것이나, 사실 신경쓰지 않아도 된다. 정그래도 신경쓰이거나, 상관이 있는 경우에는 signed나 unsigned을 써주자. 절대 기본적으로 무부호인지, 유부호일것이라고 가정하지 말라.
toupper()가 대표적이다.
scanf를 통해서 다음과 같이 문자를 입력하는 경우, 공백을 스킵하지 않고 공백을 저장한다.
char ch;
scanf("%c", &ch);
따라서 scanf(" %c", &ch);로 변경해주면 공백이 입력되더라도, 공백이 ch에 입력되지 않는다.
사실 scanf/printf말고 getchar/putchar를 사용해도 된다. 이 둘은 매크로로 정의되었기 때문에 기존방법보다 훨씬 빠르다. 그리고 getchar는 int 값을 반환하기에 int에 저장해도 된다. 이 둘은 띄어쓰기를 스킵하지 않는다.