여러 다른 답변에에 감동하지만 같은 첫째, 충분히 명확하게 밖으로 철자 내 마음에 : 그것은 수행 의 정수 제공하는 일을 대부분의 라이브러리 함수가 걸리는 상황 double
이나 float
인수를. 컴파일러는 자동으로 변환을 삽입합니다. 예를 들어, sqrt(0)
는 잘 정의되어 있고 정확히으로 작동 sqrt((double)0)
하며 여기에서 사용되는 다른 정수 유형 표현식에 대해서도 마찬가지입니다.
printf
은 다르다. 가변적 인 수의 인수를 취하기 때문에 다릅니다. 기능 프로토 타입은 다음과 같습니다.
extern int printf(const char *fmt, ...);
따라서 당신이 쓸 때
printf(message, 0)
컴파일러에는 두 번째 인수가 어떤 유형이 printf
될 것으로 예상 하는지에 대한 정보가 없습니다 . 인수 표현식의 유형 () 만 int
있습니다. 따라서 대부분의 라이브러리 함수와 달리 인수 목록이 형식 문자열의 예상과 일치하는지 확인하는 것은 프로그래머의 책임입니다.
(최신 컴파일러 는 형식 문자열을 조사하여 유형 불일치가 있음을 알려줄 수 있지만, 의미 한 바를 달성하기 위해 변환 삽입을 시작하지는 않을 것입니다. , 덜 유용한 컴파일러로 다시 빌드했을 때보 다 몇 년 후.)
이제 질문의 나머지 절반은 다음과 같습니다. 대부분의 최신 시스템에서 (int) 0과 (float) 0.0이 모두 0 인 32 비트로 표시된다는 점을 감안할 때 우연히 작동하지 않는 이유는 무엇입니까? C 표준은 "이것은 작동하는 데 필요하지 않습니다. 당신은 스스로 할 수 있습니다."라고 말하고 있지만 작동하지 않는 가장 일반적인 두 가지 이유를 설명하겠습니다. 이것이 왜 필요하지 않은지 이해하는 데 도움이 될 것입니다 .
첫째, 역사적 이유로 float
변수 인수 목록 을 통과하면 대부분의 최신 시스템에서 64 비트 너비 인로 승격 됩니다 . 따라서 64 개를 예상하는 수신자에게 32 개의 0 비트 만 전달합니다.double
printf("%f", 0)
두 번째로 중요한 이유는 부동 소수점 함수 인수가 정수 인수 와 다른 위치에 전달 될 수 있다는 것입니다. 예를 들어, 대부분의 CPU에는 정수 및 부동 소수점 값에 대한 별도의 레지스터 파일이 있으므로 인수 0 ~ 4가 정수인 경우 레지스터 r0 ~ r4에 들어가고, 부동 소수점 인 경우 f0 ~ f4에 들어가는 것이 규칙 일 수 있습니다. 따라서 printf("%f", 0)
레지스터 f1에서 0을 찾습니다.하지만 전혀 없습니다.
printf
는을 (를) 예상하고double
있으며int
.float
및int
컴퓨터에 같은 크기 일 수 있지만0.0f
실제로 변환되는double
가변 인자 인수 목록에 밀려 (때printf
기대하는). 요컨대,printf
사용하는 지정자와 제공하는 인수를 기반으로하여 협상의 끝을 이행하지 않습니다 .