인쇄F 형식 문자열

printf format string
인쇄 기능 예제

printf 형식 문자열C와 많은 다른 프로그래밍 언어의 입출력 라이브러리에서 기능 클래스가 사용하는 제어 매개변수를 말한다. 문자열은 단순한 템플릿 언어로 작성된다: 문자는 보통 문자 그대로 함수의 출력에 복사되지만, 문자로 시작하는 형식 지정자는 데이터 조각(숫자 등)을 문자로 번역하는 위치와 방법을 나타낸다.

"printf"는 주요 C 출력 기능 중 하나의 명칭으로, "print formated"의 약자로, printf 형식 문자열은 scanf 형식 문자열과 상호 보완되어 형식화된 입력(파싱)을 제공한다. 두 경우 모두 보다 정교하고 유연한 템플릿 엔진이나 파서들에 비해 단순한 기능성과 고정형식을 제공하지만, 여러 용도로는 충분하다.

C 이외의 많은 언어는 인쇄f 형식 문자열 구문을 자신의 I/O 함수에 밀접하게 또는 정확하게 복사한다.

형식 지정자와 데이터 유형이 일치하지 않으면 충돌 및 기타 취약성이 발생할 수 있다. 형식 문자열 자체는 함수 호출의 정적 분석이 가능한 문자열 리터럴인 경우가 매우 많다. 그러나 동적 형식을 허용하는 변수의 값일 수도 있지만 제어되지 않는 형식 문자열 공격이라고 알려진 보안 취약성 또한 허용할 수 있다.

역사

포트란과 같은 초기 프로그래밍 언어들은 포맷 설명을 작성하기 위해 다른 계산과는 전혀 다른 구문을 가진 특수문을 사용했다. 이 예에서 형식은 601번 라인에서 지정되며, WRITE 명령은 이를 라인 번호별로 가리킨다.

      쓰기 출력 테이프 6, 601, IA, IB, IC, 영역  601  포맷 (4H A= ,I5,5H  B= ,I5,5H  C= ,I5,      &        8H  영역= ,F10.2, 13H 사각형 단위) 

ALGOL 68은 더 기능적인 API를 가지고 있었지만, 여전히 특수 구문(the special syntax)을 사용했다. $ 구분 기호가 특수 형식 구문을 둘러싸고 있음:

활자화하다(($"색깔"g", 1번 "6d,", 2번 "4zd,", 16진수 "16r2d,", float "-d.2d,", 서명되지 않은 값"-3d"."l$,          "빨간색", 123456, 89,  255, 3.14, 250)); 

그러나 정상 함수 호출과 데이터 유형을 사용하면 언어와 컴파일러를 단순화하고 입력/출력 구현을 동일한 언어로 작성할 수 있다. 이러한 이점은 단점(많은 경우 유형 안전성의 완전한 결여 등)을 능가하며 대부분의 새로운 언어에서 I/O는 구문의 일부가 아니다.

C의 printf기원은 BCPL에 있다. writef 기능을 하다 에 비해 C 그리고 printf, *N 뉴라인 문자를 나타내는 BCPL 언어 이스케이프 시퀀스(C가 이스케이프 시퀀스를 사용함) \n) 및 형식 지정의 필드 너비와 형식 순서가 역순으로 표시됨 writef:[1]

WRITF("%I2-QENS 문제 %I5 솔루션*N", NUMKENS, 카운트) 

아마도 C 언어 이외의 구문의 첫 번째 복사는 Unix였을 것이다. printf 버전 4에서 C에 대한 포트의 일부로 처음 나타난 셸 명령.[2]

자리 표시자 지정 형식 지정

형식 지정은 형식 문자열 내의 자리 표시자를 통해 이루어진다. 예를 들어, 프로그램이 사람의 나이를 출력하고자 한다면, "당신의 나이는"으로 접두사를 붙이고 서명된 십진수 지정자를 사용하여 출력물을 제시할 수 있다. d 메시지 직후 연령에 대한 정수를 표시하기를 원한다는 것을 나타내기 위해, 우리는 다음 형식 문자열을 사용할 수 있다.

활자화하다("당신의 나이는 %d", 나이를 먹다); 

구문

형식 자리 표시자의 구문은 다음과 같다.

%[nump][nump][width][.nump][length] 유형

매개변수 필드

이것은 POSIX 확장이며 C99에서는 아니다. 매개변수 필드는 생략하거나 다음과 같을 수 있다.

캐릭터 설명
$ n은 이 형식 지정자를 사용하여 표시할 매개 변수의 수입니다. 제공된 매개 변수는 다양한 형식 지정자를 사용하거나 다른 순서로 여러 번 출력할 수 있다. 단일 자리 표시자가 매개 변수를 지정하는 경우 나머지 모든 자리 표시자도 매개 변수를 지정해야 한다.
예를 들어, printf("%2$d %2$#x; %1$d %1$#x",16,17) 생산하다 17 0x11; 16 0x10.

이 특징은 주로 언어에 의존하는 관습으로 인해 매개변수의 발생 순서가 달라지는 국산화에서 그 사용을 본다.

비 POSIX Microsoft Windows에서 이 기능에 대한 지원은 별도의 printf_p 함수에 배치된다.

깃발 필드

플래그 필드는 다음 중 0 이상일 수 있다(순서에 관계없이).

캐릭터 설명
-
(iii)
이 자리 표시자의 출력을 왼쪽 정렬하십시오. (기본값은 출력을 오른쪽 정렬하는 것이다.)
+
(더하기)
양수 서명 숫자 유형의 경우 플러스 값 추가. 양수 = +, 음수 = -.
(기본값은 양수 앞에 아무것도 선행하지 않는다.)

(공간)
양의 부호화된 숫자 유형을 위한 공간 준비. 양수 = , 마이너스 = -. 이 플래그는 + 플래그가 존재할 경우 무시된다.
(기본값은 양수 앞에 아무것도 선행하지 않는다.)
0
(0)
'width' 옵션을 지정하면 숫자 유형에 대해 0을 앞에 붙인다. (기본값은 공백 앞에 있음)
예를 들어, printf("%4X",3) 생산하다 3하는 동안에 printf("%04X",3) 생산하다 0003.
'
(apostrophe)
소수점 정수 또는 지수에는 수천 개의 그룹화 구분 기호가 적용된다.
#
(iii)
대체 양식:
G형G형의 경우 후행 0은 제거되지 않는다.
f, F, e, E, g, G 유형의 경우 출력에는 항상 소수점이 포함된다.
o, x, X 유형의 경우 각각 0, 0x, 0X 텍스트가 0이 아닌 숫자로 앞에 붙는다.

폭장

Width 필드는 출력할 최소 문자 수를 지정하며, 일반적으로 표로 된 출력에서 고정 너비 필드를 채우는 데 사용되며, 그렇지 않으면 크기가 큰 필드가 잘리지 않지만 필드가 더 작을 수 있다.

너비 필드는 생략하거나, 숫자 정수 값, 또는 별표로 표시될 때 다른 인수로 전달될 때 동적 값을 생략할 수 있다.[3] printf("%*d", 5, 10) 결국에 이르게 될 것이다. 10 인쇄할 때, 총 너비가 5자 입니다.

너비 영역의 일부는 아니지만 선행 0은 위에서 언급한 제로 패딩 플래그로 해석되며, 음의 값은 왼쪽 정렬과 함께 양의 값으로 처리된다. 또한 위에서 언급한 플래그도 있다.

정밀장

정밀도 필드는 일반적으로 특정 형식 지정 유형에 따라 출력에 대한 최대 제한을 지정한다. 부동 소수점 숫자 유형의 경우 출력을 반올림해야 하는 소수점 오른쪽의 자릿수를 지정한다. 문자열 유형의 경우 출력해야 하는 문자 수를 제한하고 그 후에 문자열이 잘린다.

정밀도 필드를 생략하거나, 숫자 정수 값 또는 다른 인수로 전달될 때 동적 값을 별표(*)로 표시할 수 있다. 예를 들어, printf("%.*s", 3, "abcdef") 결국에 이르게 될 것이다. abc 인쇄 중인

길이 필드

길이 필드는 생략하거나 다음 중 하나일 수 있다.

캐릭터 설명
hh 정수 유형의 경우, 인쇄물문자에서 승격된 크기 내 정수 인수를 예상하게 한다.
h 정수 유형의 경우, 에서는 printf짧은 시간에서 승격된 크기 내 정수 인수를 예상하게 한다.
l 정수 유형의 경우, printf가 긴 크기의 정수 인수를 기대하게 한다.

부동 소수점 유형의 경우 이 값은 무시된다. 플로트 논거는 항상 바그스 호출에 사용될 때 두 로 승격된다.[4]

나는 정수 유형의 경우, printf가 긴 크기의 정수 인수를 기대하게 한다.
L 부동 소수점 유형의 경우, printf가 긴 이중 인수를 기대하게 한다.
z 정수 유형의 경우, printf가 size_t 크기의 정수 인수를 기대하게 한다.
j 정수 유형의 경우, intmax_t 크기의 정수 인수를 printf에 예상하게 한다.
t 정수 유형의 경우, ptrdiff_t 크기 정수 인수를 ptrdiff_t-size 정수 인수를 예상하게 한다.

또한 ISO C99 확장자를 광범위하게 사용하기 전에 다음과 같은 플랫폼별 길이 옵션이 존재하게 되었다.

성격. 설명
I 서명된 정수 유형의 경우 ptrdiff_t 크기 정수 인수를 ptrdiff_t 크기 정수 인수를 예상하게 하고, 서명되지 않은 정수 유형의 경우 printfsize_t 크기 정수 인수를 예상하게 한다. 일반적으로 Win32/Win64 플랫폼에서 발견됨
I32 정수 유형의 경우 에서는 printf가 32비트(더블 워드) 정수 인수를 예상하게 한다. 일반적으로 Win32/Win64 플랫폼에서 발견됨
I64년 정수 유형의 경우, printf가 64비트(쿼드 워드) 정수 인수를 예상하게 한다. 일반적으로 Win32/Win64 플랫폼에서 발견됨
q 정수 유형의 경우, printf가 64비트(쿼드 워드) 정수 인수를 예상하게 한다. BSD 플랫폼에서 흔히 발견된다.

ISO C99에는 다음이 포함된다. inttypes.h 플랫폼에 독립적인 여러 매크로가 포함된 헤더 파일 printf 부호화 예를 들어, 이중 인용문 밖에 있어야 한다. printf("%" PRId64 "\n", t);

매크로의 예로는 다음과 같다.

매크로 설명
PRId32 일반적으로 I32d(Win32/Win64) 또는 d와 동일함
PRId64 일반적으로 I64d(Win32/Win64), lld(32비트 플랫폼) 또는 ld(64비트 플랫폼)와 동일함
PRI32 일반적으로 I32i(Win32/Win64) 또는 I와 동일함
PRI64 일반적으로 I64i(Win32/Win64), lli(32비트 플랫폼) 또는 li(64비트 플랫폼)와 동일함
PRIu32 일반적으로 I32u(Win32/Win64) 또는 u와 동일함
PRIu64 일반적으로 I64u(Win32/Win64), llu(32비트 플랫폼) 또는 lu(64비트 플랫폼)와 동일함
PRIx32 일반적으로 I32x(Win32/Win64) 또는 x와 동일
PRIx64 일반적으로 I64x(Win32/Win64), llx(32비트 플랫폼) 또는 lx(64비트 플랫폼)와 동일함

유형 필드

유형 필드는 다음 중 하나일 수 있다.

캐릭터 설명
% 리터럴 % 문자 인쇄(이 유형은 플래그, 너비, 정밀도, 길이 필드를 사용할 수 없음)
d, i %d%i은(는) 출력의 동의어지만 와 함께 사용할 때 다르다. scanf 입력(%i를 사용하면 0x가 앞에 있으면 16진수로, 0이 앞에 있으면 8진수로 해석)
u 부호 없는 십진법을 인트로 인쇄하십시오.
F, F 정규(고정점) 표기법에서 이중. fF는 무한수 또는 NaN에 대한 문자열이 인쇄되는 방식에만 차이가 있다(f의 경우 인피니티, nan; F의 경우 INF, Infinity, NAN).
E, E 표준형식의 이중 값(d.ddde±dd). E 변환은 E(e가 아닌) 문자를 사용하여 지수를 도입한다. 지수는 항상 최소 두 자리수를 포함하며, 값이 0이면 지수는 00이다. Windows에서, 지수에는 예를 들어 1.5e002와 같이 기본적으로 세 개의 숫자가 포함되지만, 이것은 Microsoft에 의해 변경될 수 있다. _set_output_format 기능을 하다
G, G 정규 표기법이나 지수 표기법 중 어느 것이든 그 크기에 더 적합한 것이어야 한다. g는 소문자를 사용하고, G는 대문자를 사용한다. 이 형식은 소수점 오른쪽의 경미한 영이 포함되지 않는다는 점에서 고정점 표기법과 약간 다르다. 또한 소수점은 정수에 포함되지 않는다.
X, X 16진수서명되지 않은. x는 소문자를 사용하고 X는 대문자를 사용한다.
o 팔분의 일자서명하지 않은
s null-instring 문자열
c 글씨를 쓰다
p 구현 정의 형식의 void* (void to void)
A, A 0x 또는 0X로 시작하는 16진법 표기법에서 이중으로 표시된다. a는 소문자를 사용하고, A는 대문자를 사용한다.[5][6] (C++11 iostreams는 동일한 기능을 하는 16진법을 가지고 있다.)
n 아무것도 인쇄하지 않고 지금까지 쓴 문자 수를 정수 포인터 매개 변수에 기록하십시오.
자바에서 이것은 새로운 선을 인쇄한다.[7]

사용자 지정 형식 자리 표시자

몇 가지 구현이 있다. printf-탈출 문자 기반 미니언어에 대한 확장을 가능하게 하여 프로그래머가 비-빌트인 유형에 대한 특정 포맷 기능을 가질 수 있도록 하는 기능. 가장 잘 알려진 것 중 하나는 glibc의 (지금은 더 이상 사용되지 않는) glibc이다. 그러나 정적 형식 문자열 확인과 충돌해 거의 사용하지 않는다. 또 다른 것은 Vstr 사용자 지정 포맷터인데, 다중 문자 포맷 이름을 추가할 수 있다.

Apache HTTP 서버와 같은 일부 응용 프로그램에는 자체 응용 프로그램이 포함됨 printf-기능과 유사하고, 그 안에 확장을 내장한다. 그러나 이 모든 것들은 같은 문제를 가지고 있는 경향이 있다. register_printf_function() 가지다

리눅스 커널 printk 함수는 일반을 사용하여 커널 구조를 표시하는 여러 가지 방법을 지원한다. %p 추가 형식 문자를 추가하여 사양.[8] 예를 들어, %pI4 IPv4 주소를 점 십진법으로 인쇄한다. 이렇게 하면 (의) 정적 형식 문자열을 검사할 수 있다. %p 부분) 일반 인쇄물과의 완전한 호환성을 희생해야 한다.

대부분의 언어에는 다음이 있음 printf-라이크 기능은 이 기능의 부족을 단지 사용으로 해결할 수 있다. %s 객체를 문자열 표현으로 포맷하고 변환한다.

취약성

잘못된 변환 사양

템플릿 문자열의 모든 변환 규격에 대한 값을 제공할 수 있도록 함수 인수가 너무 적거나 인수가 올바른 유형이 아닌 경우 정의되지 않은 결과가 충돌할 수 있다. 구현은 문자열의 구문 오류가 인수를 사용하는지 여부와 인수를 사용하는 유형에 대해 일관성이 없다. 과도한 주장은 무시된다. 정의되지 않은 동작으로 인해 "포맷 문자열 공격" 보안 취약성이 발생한 경우도 적지 않다. 대부분의 C 또는 C++ 호출 규칙 인수는 스택에 전달될 수 있으며, 이는 인수가 너무 적은 경우 인쇄 f가 현재 스택 프레임의 끝을 지나 읽으므로 공격자가 스택을 읽을 수 있음을 의미한다.

GNU Compiler Collection과 같은 일부 컴파일러는 printf와 유사한 기능의 형식 문자열을 정적으로 검사하고 (플래그 사용 시) 문제를 경고한다. -Wall 또는 -Wformat) 또한 GCC는 비표준 "형식"인 경우 사용자 정의 인쇄f 스타일 기능에 대해 경고한다. __attribute__ 기능에 적용됨.

필드 너비 대 표 출력의 명시적 구분 기호

다음과 같은 형식과 같이 필드 너비만 사용하여 테이블링 제공 %8d%8d%8d 3개의 8자 열에서 3개의 정수에 대해, 데이터에 많은 수가 발생하는 경우 필드 분리가 유지된다는 보장은 없다. 필드 분리의 손실은 쉽게 출력의 손상을 초래할 수 있다. 스크립트의 구성 요소로서 프로그램을 사용하도록 권장하는 시스템에서, 그러한 손상된 데이터는 원본 프로그래머가 출력물이 사람의 눈으로만 읽힐 것으로 예상했는지 여부에 관계없이 종종 전달되고 더 이상의 프로세싱이 손상될 수 있다. 이러한 문제는 모든 표 형식에 명시적인 구분자, 짝수 공백 등을 포함함으로써 제거할 수 있다. 단순히 위험한 예를 이전에서 이전으로 바꾸는 것 %7d %7d %7d 숫자가 커질 때까지 동일하게 포맷하되, 명시적으로 포함된 공간 때문에 출력에 병합되는 것을 명시적으로 방지한다. 문자열 데이터에도 유사한 전략이 적용된다.

메모리 쓰기

표면의 출력 기능도 있지만, printf 다음을 통해 인수에 의해 지정된 메모리 위치에 쓰기 허용 %n. 이 기능은 때때로 보다 정교한 형식 문자열 공격의 일부로 사용된다.[9]

%n 기능도 만든다. printf 우연히 잘 구성된 일련의 논쟁에도 불구하고 튜링 작업이 완료됨. 형식 문자열로 작성된 틱택토 경기는 제27회 IOCCC의 우승자.[10]

printf로 언어 프로그래밍

글의 형식 문자열에서 벗어나는 형식 문자열(AMP, Elixir 등), JVM 또는 기타 환경(Clojure, Scala 등)을 사용하는 언어, 표준 네이티브 인쇄F 구현은 없지만 인쇄F 동작을 에뮬레이트하는 외부 라이브러리가 있는 언어 JavaScript)는 이 목록에 포함되지 않는다.

참고 항목

참조

  1. ^ "BCPL". cl.cam.ac.uk. Retrieved 19 March 2018.
  2. ^ McIlroy, M. D. (1987). A Research Unix reader: annotated excerpts from the Programmer's Manual, 1971–1986 (PDF) (Technical report). CSTR. Bell Labs. 139.
  3. ^ "printf - C++ Reference". cplusplus.com. Retrieved 10 June 2020.
  4. ^ ISO/IEC(1999년). ISO/IEC 9899:1999(E): 프로그래밍 언어 - C 제7.19.6.1항 7
  5. ^ ""The GNU C Library Reference Manual", "12.12.3 Table of Output Conversions"". Gnu.org. Retrieved 17 March 2014.
  6. ^ "인쇄" (C99에 %a 추가)
  7. ^ "Formatting Numeric Print Output". The Java Tutorials. Oracle Inc. Retrieved 19 March 2018.
  8. ^ "Linux kernel Documentation/printk-formats.txt". Git.kernel.org. Retrieved 17 March 2014.
  9. ^ https://www.exploit-db.com/docs/english/28476-linux-format-string-exploitation.pdf
  10. ^ https://www.ioccc.org/2020/carlini/index.html
  11. ^ "Printf Standard Library". The Julia Language Manual. Retrieved 22 February 2021.
  12. ^ "Built-in Types: printf-style String Formatting", The Python Standard Library, Python Software Foundation, retrieved 24 February 2021

외부 링크