
본 포스팅은 Stephen Prata의 C Primer Plus를 읽고 요약한 글입니다.
#include <stdio.h>
int main(void)
{
float weight, value;
printf("몸무게 입력하시오. (파운드 단위)\n");
scanf("%f", &weight);
value = 1700.0 * weight * 14.5833;
printf("플래티넘 가치로 환산한 당신의 몸값: %.2f\n", value);
return 0;
}
| K&R C 키워드 | C90 K&R 키워드 | C99 키워드 |
|---|---|---|
| int, long, short, unsigned, char, float, double | signed, void | _Bool, _Complex, _Imaginary |
int는 C의 정수 기본형이고, long, short, unsigned, signed는 기본형 정수의 변형이다.char은 문자에 사용되며, 작은 정수들을 나타내는 데 사용할 수도 있다.float, double은 소수점이 있는 수를 나타낸다._Bool은 true와 false를, _Complex와 _Imaginary는 복소수와 허수를 나타낸다.E(exponent: 지수)을 표기하면 10ⁿ을 곱한다. (3.14E7 == 3.14 * 10ⁿ)7.0은 0.7E1로 바꿀 수 있는데, 0.7이 소수부분 이며 E1이 지수부분이다.intint는 signed integer이며, 양수, 음수, 0이 될 수 있다.int는 해당 컴퓨터의 1워드로 저장된다.int 형의 최소 범위를 32bit(-32767~32767)로 규정한다.1, 21 -39 등은 integer constant이며, integer literal이라고도 불린다. (매우 크면 long int )**int 값의 출력**int의 포맷 지정자(format sepcifier: 값을 출력하는 포맷(char)으로 변환)는 %d이다.printf() 함수는 포맷 지정자 개수와 인자 리스트의 개수가 1:1로 대응해야하지만, 맞지 않아도 에러를 검출하지 않는다. 이는 printf()는 전달인자의 개수가 확정되지 않아 컴파일러가 에러를 체크하는 통상적인 방법을 자신에게 적용되지 못하게 막는 특이한 설계로 만들어졌기 때문이다.0 / 16bit: 0x)printf()의 포맷 지정자로 8진수 %o, 16진수 %x를 사용하면 10진수 int를 해당 진수의 수로 출력하며, prefix도 함께 출력할 때는 %#o, %#x를 사용한다.#include <stdio.h>
int main(void)
{
int x = 100;
printf("decimal: %d, octal: %o, hexadecimal: %x\n", x, x, x);
printf("decimal: %d, octal: %#o, hexadecimal: %#x\n", x, x, x);
return 0;
}
short, long, unsignedshort, long, unsigned 세 개의 형용사 키워드를 제공한다.short: int보다 더 적은 메모리를 사용할 수 있기 때문에 메모리 절약 가능하다. (signed)long: int보다 더 큰 메모리를 사용할 수 있다. (signed)long long: C99표준에 추가되었는데, long보다 더 큰 메모리를 사용하며, 최소 64bit 이상을 사용해야 한다. (signed)unsigned: 음수가 아닌 값들만 가지는 변수에 사용하며, 저장할 수 있는 수의 범위가 변한다. 예를 들어 16bit unsigned int는 -32768~32767 대신 0~65335까지 범위를 사용한다. 또한 부호를 나타내던 비트가 또 하나의 2진수로 사용되어 더 큰 수를 표현한다. (포맷 지정자는 %u다.)unsigned long int(=unsigned long)와 unsigned short int(=unsigned short)를 수용하고, C99 표준은 unsigned long long int(=unsigned long long)을 추가했다.signed는 부호 있는 데이터 타입에 그 의미를 더욱 명시적으로 나타내야 할 때 사용한다.short는 int보다 길지 않고, long은 int보다 짧지 않다는 것만 보장한다.long long은 64bit, long은 32bit, short는 16bit로 설정하고 int는 시스템 고유 워드 크기에 따라 16 또는 32bit로 설정하기 때문이다. 즉 실제적으로는 일부 데이터 타입이 겹치고 있다.short와 int는 둘 다 -32,767~32,767 이며, 16bit 단위에 해당한다.long의 최소 범위는 -2,147,483,647~2,147,483,647 이며, 32bit 단위에 해당한다.unsigned short와 unsigend int의 최소 범위는 0~65,535 이며,unsinged long의 최소 범위는 0~4,294,967,295 이다.long long의 최소 범위는 -9,223,372,036,854,775,807~9,223,372,036,854,775,807 이며,unsigned long long의 최소 범위는 0~18,446,744,073,709,551,615 이다. (1884경)unsigned는 음수가 없고 더 큰 범위의 양수를 가지므로 수를 카운트 할 때 사용한다.long은 int로는 다룰 수 없는 큰 수를 다룰 때 사용한다. 하지만 long이 int보다 큰 시스템에서 long을 사용하면 계산이 느려지므로 반드시 필요한 경우 외에는 long을 사용하지 않는다.int와 long이 크기가 같을 경우, 32bit 정수를 사용해야하는데 16bit 프로세서에서도 동작하기를 원한다면 int 대신 long을 사용해야 한다. (16bit에서는 int가 16bit이므로.) 마찬가지 이유로 64bit 정수가 필요할 때는 long long을 사용해야 한다.int가 32bit인 시스템에서 16bit 값을 필요할 때는 short를 사용하는 것이 중요하다. (특히 배열)short를 사용하는 또 다른 이유는, 컴퓨터의 특정 구성 요소들에 의해 사용되는 하드웨어 레지스터들과 크기가 일치할 수 있기 때문이다.unsigned int는 0, signed int는 (일반적으로) 음의 최소값부터 다시 시작한다.unsigned int에 대한 규칙만 강제하기 때문에 signed int는 결과가 다를 수도 있다.long 상수와 long long 상수int 보다 큰 수를 사용하는 경우, 컴파일러는 long int로 가정하며 long 최대값도 초과할 경우, unsigned long → long long → unsigned long 순으로 취급한다. (8진수, 16진수도 같다.)long int로 저장하기도 하며, 일부 C 표준 함수들이 long 값을 요구하기도 한다.long 타입으로 취급할 때는 L을 suffix로 붙인다. (unsigned 일 때는 UL, LU)int, 32bit long을 사용하는 시스템에서 7은 16bit, 7L은 32bit로 취급된다.long long 타입을 지원하는 시스템에서는 LL을 suffix로 사용할 수 있다. (unsigned일 때는 ULL, LLU)%ld인데, int와 long이 같은 크기일 때는 %d로도 가능하지만 호환성에 안 좋다.long 타입의 8진수, 16진수를 출력할 때는 %lo, %lx을 사용한다. (포맷 지정자는 소문자가 관례.)short 타입은 %h, %ho, %hx를 사용한다.unsigned int를 %u가 아닌 %d로 지정하면, signed int의 최댓값을 초과할 경우, 원하지 않는 값이 출력된다. (long, long long 값에 다른 지정자를 사용하면 컴파일 에러를 발생시킨다.)short int는 %h이든 %d이든 동일한 값이 출력되는데, 이는 C가 short 값이 함수에 인자로 전달될 때, 컴퓨터가 가장 효율적으로 처리할 수 있는 정수 크기인 int로 short 값을 변환하기 때문이다.#include <stdio.h>
int main(void)
{
unsigned int un = 3000000000;
short end = 255;
long big = 65337;
long long verybig = 12345678912345;
printf("un = %u and not %d\n", un, un); // 3000000000 1
printf("end = %hd and %d\n", end, end); // 255 255
// printf("big = %ld and not %hd\n", big, big);
// 컴파일 에러 발생: long 변수에 short 지정자 불가능
// printf("verybig = %lld and not %ld\n", verybig, verybig);
// 컴파일 에러 발생: long long 변수에 long 지정자 불가능
return 0;
}
charchar는 문자들을 저장하는 데 사용되지만, 기술적으로 볼 때 char는 정수형인데, 실제로는 문자가 아닌 정수들을 저장하기 때문이다.ASCII, Unicode)을 사용한다.ASCII: 0부터 127까지의 정수(7bit)에 해당하는 범위이며, char는 8bit이므로 전부 담을 수 있다.Unicode: ISO/IEC 10646 표준을 준수하는 코드값으로, 약 42억(32bit)의 범위에 해당한다.char) 상수는 무조건 작은 따옴표(’’)를 사용해야하며, 큰 따옴표(“”)는 문자열로 인식한다.char 변수에 int 상수를 대입하면 이에 해당하는 (시스템이 ASCII를 사용하는 경우) 문자를 넣는다.char가 아닌 int로 취급하기 때문에 ‘FATE’와 같은 32bit(8bit*4) 문자 상수도 정의할 수 있다. 하지만 이것을 char 변수에 대입하면 마지막 8bit만 사용되기 때문에 ‘E’값만 얻게 된다.warning: implicit conversion from 'int' to 'char' changes value
from 1178686533 to 69 [-Wconstant-conversion]
# 현재는 컴파일 에러가 발생하여 직접적으로 동작하지는 않지만,
# 문자 상수가 'int'라는 것과 변환된 값이 69(='E')인 것을 볼 수 있다.ASCII 코드 중 일부는 출력되지 않는 문자들은 ASCII 코드 값(정수), escape sequence로 표현한다.\, ‘, “를 문자열 안에서 사용할 때 이스케이프 시퀀스가 꼭 필요하다.‘\007’, ‘\x010’ 식으로 표현한다.ASCII 코드 보다는 이스케이프 시퀀스를 사용하는 것이 이식하기에 더 용이하다.char 변수는 1byte 정수값으로 저장되기 때문에 %d로 지정하면 해당 ASCII 코드 값의 정수를 출력하며, 마찬가지로 int 변수 역시 %c로 지정하면 해당 ASCII 코드 문자를 출력할 수 있다.#include <stdio.h>
int main(void)
{
char ch;
int num;
printf("Enter any character: ");
scanf("%c", &ch); // E
printf("ASCII code value of charcter %c is %d.\n", ch, ch); // E 65
printf("Enter any number less then 255: ");
scanf("%d", &num); // 65
printf("ASCII code of number %d is %c.\n", num, num); // 65 E
return 0;
}
char이 signed(-128~127)일 수도, unsigned(0~255)일 수도 있다.char이 무엇이든 상관없이, 키워드를 붙여 signed char, unsigned char를 사용하도록 허용하고 있으며, 이는 작은 정수를 다룰 때 유용하다.char를 쓰는 것이 낫다._Booltrue와 false를 나타낸다.1로 true를, 0으로 false를 나타내기 때문에, 실제로는 _Bool 역시 int 타입이다.