Programing

왜 float에 대한 지정자가 printf에 정의되지 않았는가?

c10106 2022. 4. 20. 21:38
반응형

왜 float에 대한 지정자가 printf에 정의되지 않았는가?

그럴 수도 있었을 것 같은데, (적어도 C99에는) 길이 수식어가 적용 가능한 것 같다.int:%hhd%hd%ld그리고%lld심술궂다signed charshortlong그리고long long에 적용되는 길이 수식어도 있다.double:%Lf수단long double.

문제는 왜 그들이 누락했는가 하는 것이다.float대로라면, 였을 이다.%hf.

ISO C11 표로 ,로터,6.5.2.2 Function calls /6그리고/7, 표현식의 맥락에서 함수 호출에 대해 논함(나의 강조):

6/ 호출된 함수를 나타내는 식이 프로토타입을 포함하지 않는 유형을 갖는 경우, 각 인수에 정수 승진이 수행되며, 유형 부동이 있는 인수는 2배로 승격된다. 이를 기본 인수 프로모션이라고 한다.

7/ 호출된 함수를 나타내는 식에 프로토타입이 포함된 형식이 있는 경우, 각 매개변수의 유형을 선언된 형식의 부적격 버전으로 취하면서 해당 매개변수의 유형을 할당에 의해 암시적으로 변환한다.함수 프로토타입 선언기의 줄임표 표기법은 인수 유형 변환을 마지막으로 선언된 파라미터 이후에 중지하게 한다.기본 인수 승진은 후행 인수에서 수행된다.

이것은 어떤 것이든 라는 것을 의미한다.float그 후의 논쟁....에서는, 「로다」로한다.double그리고printf통화 패밀리는 그렇게 정의된다.7.21.6.11et seq:

int fprintf(FILE * restrict stream, const char * restrict format, ...);

그러니까, 할 수 있는 방법이 없기 때문에.printf()-가족이 실제로 부동액을 받으려고 전화하는 것, 그것에 대한 특별한 형식 지정자(또는 수식어)가 있다는 것은 말이 안 된다.

C 가 다양한 C가 가능하기 때문이다.float논거가 a로 승격(즉, 변환)된다.double그렇게printfA을 얻고 있다.double그리고 사용할 것이다.va_arg(arglist, double)구현에 포함시킬 수 있을 겁니다.

, 에서는 매 과(C89, K&R C)이 모모이다.float논쟁은 a로 전환되었다.double현행 표준은 명시적 프로토타입이 있는 고정된 아리티 기능에 대해 이 프로모션을 생략한다.그것은 이 구현의 ABI & 호출 규약과 관련이 있다(그리고 세부사항은 설명되어 있다).현실적으로 말하면 afloat인수로 전달될 때 값이 종종 이중 섀시 포인트 레지스터에 로드되지만 세부 사항은 다를 수 있다.예를 들어 Linux x86-64 ABI 규격을 읽어 보십시오.

또한, 특정 형식 제어 문자열을 제공할 실질적인 이유가 없다.float출력 너비를 조정할 수 있기 때문에(예:%8.5f) 원하는 대로, 그리고%hd훨씬 더 유용하다(필요하다)scanf에 있어서보다printf

그 너머로는 (누락해야 할) 이유가 있을같다.%hf지만 float-에 대한 제한double에 하여.printf)은 역사적이다: 처음에 C는 HPC가 아니라 시스템 프로그래밍 언어였다(Fortran은 아마도 1990년대 후반까지 HPC에서 선호되었다).float별로 중요하지 않았다; 그것은 (그리고 지금도) 같은 생각이었다.short메모리 소비를 줄이는 방법.그리고 오늘날의 FPU는 (데스크톱 또는 서버 컴퓨터에서) 사용할 수 있을 만큼 빠름float기억력을 줄이기 위한 수단일 뿐이지기본적으로 당신은 모든 사람이float(아마도 FPU 또는 CPU 내부)로 변환된 위치double.

사실, 당신의 질문은 다음과 같은 말로 표현될 수 있다: 왜%hd을 위해 존재하다.printf(근본적으로 쓸모없는 곳, 그 이후부터)printf을 얻고 있다.int조금면 면면 .short그러나scanf!) 할 것 이유는 모르겠지만, 시스템 프로그래밍보다 더 유용할 것 같아.

은 C할 수 .%hf에 의해 받아들여지다.printf을 위해float에)double에서printf전화 같은 것short-s가 로 승진하다.int)) 이중 정밀도 값이 범위를 벗어날 때 정의되지 않은 동작으로float -s, thoughly symetrically.%hf에 의해 받아들여지다.scanf을 위해float포인드. 을 빈다행운을 빌어요.

기본 인수 승급 때문에.

printf()수능 인맥)이다....그 서명으로), 모두float논거가 로 승격되다.double.

C11 §6.5.2.2 함수 호출

6 호출된 함수를 나타내는 식이 프로토타입을 포함하지 않는 유형을 갖는 경우, 각 인수와 유형이 있는 인수에 대해 정수 승진이 수행된다.float로 승진하다.double 이를 기본 인수 프로모션이라고 한다.

7 함수 프로토타입 선언기의 줄임표 표기법은 인수 유형 변환을 마지막으로 선언된 매개변수 이후에 중지하게 한다.기본 인수 승진은 후행 인수에서 수행된다.

변수 함수를 호출할 때 기본 인수 프로모션으로 인해 값이 함수 호출 이전으로 암시적으로 변환되며 값을 전달할 방법이 없다.float에 가치를 두다.printf, 에 대한 명시적 형식 지정자가 필요 없음float가치

그런 말을 한 앙투안엘은 다음과 같은 논평에서 흥미로운 점을 꺼냈다.%lf(현재 에 사용됨scanf인 에에 double *)은 한때 "을 의미했을지도 모른다.long floatC99 이론의 42페이지에 따르면, C89일 이전의 동의어 형식이었다.그 논리로 보면, 이치에 맞을지도 모른다.%fA을 지지하기 위한 것이었다.float로 한 값double.


에 관하여hh그리고h길이 한정자,%hhu그리고%hu다음 형식 지정자에 대해 잘 정의된 사용 사례를 제시하십시오.라지 중에서 가장 중요하지 않은 바이트를 인쇄할 수 있다.unsigned int또는unsigned short예를 들어, 깁스를 하지 않은 경우:

printf("%hhu\n", UINT_MAX); // This will print (unsigned char)  UINT_MAX
printf("%hu\n",  UINT_MAX); // This will print (unsigned short) UINT_MAX

로부터의 좁은 전환은 특별히 잘 정의되어 있지 않다.intchar또는short결과적으로, 그러나 그것은 적어도 구현이 정의된다. 즉, 구현이 이 결정을 실제로 문서화하는 데 필요함을 의미한다.

패턴대로라면 그랬어야 했는데%hf.

당신이 관찰한 패턴을 따라%hf다음 범위를 벗어나는 값을 변환해야 함float로 돌아가다.float하지만, 그런 종류의 변환은doublefloat 정의되지 않은 행동을 하게 되고, 그런 행동은 없다.unsigned float. 보이는 패턴은 말이 안 된다.


공식적으로 옳게 말하자면%lfa를 나타내지 않는다.long double그리고 만약 당신이 A를 통과한다면long double정의되지 않은 행동을 유발할 수 있다는 주장문서에는 다음과 같은 내용이 명시되어 있다.

l(엘) ...다음 사항에 영향을 미치지 않다.a,A,e,E,f,F,g또는G전환 지정자

아무도 이걸 알아채지 못했다니 놀랍군? %lfa를 나타내다double마치 논쟁처럼%f. 인쇄하려면long double, 사용%Lf(자본 타원).

이제 와서는 이치에 맞다.%lf양자를 위하여printf그리고scanf에 해당하다double그리고double *논쟁들... %f앞에서 언급한 이유 때문에 기본 인수 프로모션 때문에만 예외적이다.

…과%Ld는 뜻이 아니다long어느 쪽이든그것이 의미하는 것은 정의되지 않은 행동이다.

Fscanf 아래의 C 논거를 읽어 보면 다음과 같은 것을 알 수 있다.

C99의 새로운 기능:hh 및 l 길이 한정자는 C99에 추가되었다. ll은 새로운 long int 유형을 지원한다.hh는 문자 유형을 다른 정수 유형과 동일하게 취급하는 기능을 추가한다. 이는 SCNd8 in과 같은 매크로를 구현하는 데 유용할 수 있다(7.18 참조).

그래서 아마도hh새로운 모든 것에 대한 지원을 제공하기 위해 추가되었다.stdint.h이것은 왜 작은 정수에는 길이 수식어가 추가되었지만 작은 부유물에는 추가되지 않았는지를 설명할 수 있다.

C90이 왜 일관성이 없었는지는 설명되지 않는다.h그러나 아니다hh그래도C90에 명시된 언어가 항상 일치하지는 않으며, 그렇게 간단하지 않다.그리고 이후 버전들은 모순을 물려받았다.

C가 발명되었을 때, 모든 부동 소수점 값은 공통 유형(즉, 공통 유형)으로 변환되었다.double계산에 사용되거나 함수에 전달되기 전(포함)printf, 그래서 그럴 필요가 없었다.printf부동 소수점 유형 간에 구별할 수 있다.

산술 효율성과 정확성을 촉진하기 위해 IEEE-754 부동 소수점 표준은 일반 64비트보다 큰 80비트 유형을 정의했다.double하지만 더 빨리 처리될 수 있다.그 의도는 다음과 같은 표정을 지으면서였다.a=b+c+d;합계를 계산하는 것보다 모든 것을 80비트 유형으로 변환하고, 세 개의 80비트 숫자를 합산하고, 결과를 64비트 유형으로 변환하는 것이 더 빠르고 정확할 것이다.(b+c)64비트 유형으로 지정한 다음d.

새로운 유형을 지원하기 위해, ANSI C는 새로운 유형을 정의했다.long double새로운 80비트 유형 또는 64비트를 참조할 수 있는 구현double. 불행히도, IEEE-754 80비트 유형의 목적은 모든 값이 새로운 유형으로 자동 승격되도록 하는 것이었지만, 그들이 새로운 유형으로 승격된 방식이었다.double, ANSI가 그것을 만들어 새로운 타입이 전달되도록 했다.printf또는 다른 가변적 방법들이 다른 부동소수점 유형과 다르기 때문에 그러한 자동 승진이 불가능하게 된다.

따라서 C가 생성될 때 존재했던 두 부동소수점 유형은 동일한 값을 사용할 수 있다.%f형식 지정자를 지정하지만long double이후에 만들어진 것은 다른 것을 필요로 한다.%Lf형식 지정자(대소문자 포함) L).

%hhd%hd%ld그리고%lld에 추가되었다.printf형식 문자열을 보다 일관적으로 만들기 위해scanf에 대해 중복됨에도 불구하고printf기본 인수 프로모션 때문에.

그럼 왜 안 그랬어?%hf을 위해 추가된.float쉽네, 보고 있자니scanf 의 행동,float형식 지정자가 이미 있다.너무 좋다.%f. 그리고 형식 지정자.double이다%lf.

저것%lfC99가 정확히 C99에 추가한 것이다.printf C99의 의 행동.%lf정의되지 않았다(표준에서 정의가 누락됨).C99를 기준으로 하면 의 동의어다.%f.

고려하다scanf롱의 플로트, 더블이 롱 더블에 왜 플로트인지 printf비슷한 기능들이 비슷한 방식으로 구현되지 않았지만, 그렇게 해서 C / C++와 표준이 완성되었다.

프로세서와 현재 모드에 따라 푸시 또는 팝 작업을 위한 최소 크기에 문제가 있을 수 있지만, 이것은 구조물의 로컬 변수나 변수의 기본 정렬과 유사한 기본 패딩으로 처리되었을 수 있다.Microsoft에서 80비트(10바이트)에 대한 지원을 중단함long doubles 16비트에서 32비트/64비트 컴파일러로, 이제 치료long double double(64비/8바) 그들은 필요에 또는 이것은 필요에 따라 12~16바이트 경계까지 패딩할 수도 있었지만, 이 작업은 이뤄지지 않았다.

참조URL: https://stackoverflow.com/questions/32517932/why-wasnt-a-specifier-for-float-defined-in-printf

반응형