#include <stdio.h>
int main()
{
unsigned char cNum;
unsigned short sNum;
unsigned int iNum;
//char cNum;
//short sNum;
//int iNum;
cNum=-1;
sNum=-1;
iNum=-1;
printf("cNum[%d], sNum[%d], iNum[%d]\n", cNum, sNum, iNum);
return 0;
}
unsigned를 붙이면 0과 양의 정수만 표현하게 할 수 있습니다.
하지만 int는 unsigned을 입력해도 -1이 나옵니다.
%d는 10진수로 표현하란 뜻이지만 -1은 10진수가 아닙니다. 그래서 저는 %d에 문제가 있다 생각하고 여기에 중점을 두고 여러 자료를 보다 변환문자를 알게 되었습니다.
변환문자 |
의 미 |
%c |
문자 1개 출력 |
%d |
10진수로 출력 |
%e |
부호 있는 소수 출력(지수표시 e) |
%E |
부호 있는 소수 출력(지수표시 E) |
%f |
부호 있는 소수 출력 |
%g |
주어진 부호 값에 따라 f 또는 e를 자동으로 선택하여 출력 |
%G |
주어진 부호 값에 따라 F 또는 E를 자동으로 선택하여 출력 |
%ld |
long형 10진수로 출력 |
%lo |
long형 8진수로 출력 |
%lx |
long형 16진수로 출력 |
%o |
8진수로 출력 |
%s |
문자열 출력 |
%u |
부호 없는 10진수로 출력 |
%x |
16진수로 출력 (0~9,a,b,c,d,e,f) |
%X |
16진수로 출력 (0~9,A,B,C,D,E,F) |
첫 번째 생각
일단은 -1이 4294967295가 나왔으니 +1을 해서 4294967296을 나누기 2로해서
2147483648숫자가 나와 -1대신 입력해보니 -2147483648가 나왔습니다.
그래서 한번 더 +1을 더해 2147483649를 입력해보니 이번엔 결과가 2147483647로 나왔습니다. 생각해본 결과 4294967295는 2진수로 표현하면 11111111 11111111 11111111 11111111입니다. 4294967296은 1 00000000 00000000 00000000 00000000이기에 cpu가 32비트라 1은 버리고 0이 되버립니다. 그래서 64비트라면 -1을 입력해도 4294967295라는 숫자가 나왔을 것인데 32비트라 인식을 못하여 -1로 출력되어 버리는 것입니다. 만약 컴퓨터가 16비트였으면 short도 %d를 입력 했을때 -1로 나올 것입니다.
여튼 결과는 cpu의 성능으로 인해서 그런 결과 값이 나온 것입니다.
두 번째 생각
char 1바이트 8비트
short 2바이트 16비트
int 4바이트 32비트 -1을 하자니 그 앞에 있는 수4294967296은 1 00000000 00000000 00000000 00000000 32비트가 넘는 숫자라 인식을 못해 -1로 출력된다.
%o는 8진수로 출력하라는 것이니 입력하니 결과는
cNum[377], sNum[177777], iNum[37777777777]
정상적으로 출력
%x는 16진수로 출력이기 때문에 입력하니 결과는
cNum[ff], sNum[ffff], iNum[ffffffff]
역시나 정상적으로 출력
%d의 의미에 int의 범위가 초과되어 나타낼 수 없는 값이기에 -1이 나옵니다.
char 값의 표현범위는 -128~127(255개)
short 값의 표현범위는 -32768~32767(65535개)
int 값의 표현범위는 -2147483648~2147486647(4294967295개)
세 번째 생각
%d는 명확하게 말하자면 부호 있는 int형으로 출력하라는 말인데
int는 프로세서가 한 번에 처리하는 데이터 바이트입니다.
즉 변수를 지정할 때 char나 short로 지정하면 메모리는 절약되나 속도는 느려지고 int로 지정하면 메모리는 절약되지 않지만 속도눈 빨라집니다.
이말은 short는 변수 메모리는 2바이트를 먹었지만 실제 처리할 때는 4바이트에서 2바이트를 연산하여 2바이트만 추출해서 처리하며, int형은 그대로 처리한다는 것입니다.
그래서 위와 같은 현상이 일어납니다.
unsigned형은 음수가 들어갈 수가 없습니다.
그래서 cNum = 255, sNum = 65535, iNum = 4294967295 값이 들어가 있는 상태 입니다.
음수는 최상위 비트가 1 양수는 최상위 비트가 0입니다.
cNum과 sNum은 비트연산에서 우측쉬프트 하는 과정에서 최상위 비트가 0이 됩니다.
1111 1111 => 0000 0000 0000 0000 0000 0000 1111 1111 이렇게 되겠죠.(signed int로 변환)
그래서 보수 값을 줄 필요 없이 그대로 255, 65535 값이 나옵니다.
하지만 iNum은 우측쉬프트 할 필요 없으니 그대로 최상위 비트가 1입니다.
4바이트 전부가 1111 ... 로 되기 때문입니다.
최상이 비트가 1이면 음수이므로 보수값을 취해줘야 합니다.
1111) 원래값
0000) 1의 보수
+ 1) 2의 보수
0001) 2의 보수값
최상위비트가 1이였음으로 -가 붙습니다.
그리고 보수값 1이 나옵니다.
즉 -1값은 어떻게 출력하냐에 따라 부호 없는 최대값이자 부호 있는 최소값입니다.
이렇게 해서 unsigned int를 4294967295값을 signed int로 출력시켜서 -1값이 나옵니다.