printf("%f", 1.0f)와 같이 printf에 float형을 넘겨줘도 절대 printf 함수에 float형을 넘겨줄 수 없다는 재밌는 사실을 알게 됐다.

double lf = 1.0;
printf("%lf\n", lf); // double lf 사용
printf("%f\n", lf); // double에 f도 가능

위와 같이 double을 출력할 땐 %lf와 %f 둘 다 사용할 수 있는데 이건 C99에 생긴 기능으로 scanf에서 double형을 %lf로 받기 때문에 편의성?을 위해 생긴 기능이라고 한다.

종종 float은 %f, double은 %lf로 출력해야 한다는 사람들이 있는데 이건 완전한 오개념이다. 아래 사진을 봐도 f는 명확히 double을 위한 변환 명세다.

man page f 설명


그런데 float형을 출력할 때도 %f를 사용하는데 여기서 "float과 double을 같은 타입으로 인식하는 것인가?"라는 의문점과 "float의 변환 명세는 따로 없는 것인가"라는 의문점이 생긴다.


printf의 프로토 타입은 아래와 같다.

int printf ( const char * format, ... );

가변 인자 함수의 ... 부분엔 타입이 명시되지 않는다. 프로토타입에 타입이 명시되지 않은 인자들은 default argument promotions이 발생한다.
default argument promotions는 간단히 말하자면 short와 같이 int보다 작은 크기의 정수형을 int or unsigned int로 바꿔주고, float형은 double 형으로 바꿔주는 것이다. 여기서 포인터는 해당되지 않는다.


여기서 float을 위한 변환 명세가 없는 이유를 찾을 수 있다. float형을 전달받으면 이 float형은 무조건 double로 변환되게 된다. 그렇기 때문에 float을 그 자체로 출력할 수 없고, float을 위한 변환 명세는 있을 필요가 없기 때문에 존재하지 않는 것이다.

그럼 scanf에서는 왜 float을 위한 %f와 %lf로 구분되는지 의문이 생길 수 있는데 이는 float *과 double *이 넘겨지면서 포인터는 프로모션이 발생하지 않는다.


아래 참고자료에 이 부분을 참고했다.
"Function calls"
The ellipsis notation in a function prototype declarator causes argument type conversion to stop after the last declared parameter. The default argument promotions are performed on trailing arguments.
So in effect, it's impossible to pass a float to printf() - it will always be promoted to a double. That's why the format specifiers for floating point values expect a double.

참고 자료

 

Why are 4 characters allowed in a char variable? [duplicate] - c

 

www.developreference.com

 

'C++' 카테고리의 다른 글

[C/C++] 잡기술  (0) 2022.07.07
[C/C++] Sequencing (Sequence Point)  (0) 2022.05.01
[C++] lower_bound vs upper_bound  (0) 2021.10.15
[C++] string split구현  (0) 2021.09.11
[C++] Structured binding  (0) 2021.07.21
복사했습니다!