태그 보관물: libc

libc

snprintf ()는 항상 null로 종료됩니까? 항상 대상

snprintf는 항상 대상 버퍼를 종료하는 null입니까?

즉, 이것으로 충분합니까?

char dst[10];

snprintf(dst, sizeof (dst), "blah %s", somestr);

아니면 somestr이 충분히 길다면 이렇게해야합니까?

char dst[10];

somestr[sizeof (dst) - 1] = '\0';
snprintf(dst, sizeof (dst) - 1, "blah %s", somestr);

나는 표준이 말하는 것과 표준 동작이 아닌 일부 대중적인 libc가 무엇을 할 수 있는지에 관심이 있습니다.



답변

다른 답변이 설정으로 : 그것은 해야한다 :

snprintf… 결과를 문자열 버퍼에 기록합니다. (…) buf_size가 0이 아니면 널 문자로 종료됩니다.

따라서주의해야 할 것은 크기가 0 인 버퍼를 전달하지 않는 것입니다. 왜냐하면 (분명히) “nowhere”에 0을 쓸 수 없기 때문입니다.


그러나 조심 마이크로 소프트의 라이브러리가 없는 라는 함수를 snprintf대신 역사적으로 단지 라는 함수했다 _snprintf(참고 선도 밑줄) 추가하지 않습니다 종단 널 (null)입니다. 다음은 문서입니다 (VS 2012, ~~ VS 2013) :

http://msdn.microsoft.com/en-us/library/2ts7cx93%28v=vs.110%29.aspx

반환 값

len을 형식화 된 데이터 문자열의 길이 (종료 널을 포함하지 않음)로 지정하십시오. len 및 count는 _snprintf의 경우 바이트, _snwprintf의 경우 와이드 문자입니다.

  • len <count이면 len 문자가 버퍼에 저장되고 널 종료자가 추가되며 len이 리턴됩니다.

  • len = count이면 len 문자가 버퍼에 저장되고 널 종료자가 추가되지 않으며 len이 리턴됩니다.

  • len> count이면 count 문자가 버퍼에 저장되고 널 종료자가 추가되지 않고 음수 값이 리턴됩니다.

(…)

Visual Studio 2015 (VC14)는 준수 snprintf기능을 도입 한 것 같지만 선행 밑줄과 null 이 아닌 종료 동작이 있는 레거시 기능 이 여전히 존재합니다.

snprintf함수는 len이 count보다 크거나 같을 때 null 종료자를에 배치하여 출력을 자릅니다
buffer[count-1]. (…)

모든 함수 다른 보다 snprintfLEN = 카운트 경우 len 문자가 버퍼에 저장되며, 어떤 널 종결이 추가되지 않는다 (…)


답변

snprintf (3) 맨 페이지에 따름.

함수 snprintf()vsnprintf()최대 size바이트 (후행 널 바이트 ( ‘\ 0’) 포함)를 str.

예, 크기가 1보다 크면 종료 할 필요가 없습니다.


답변

버퍼 크기는 0, C 않는 표준에 따르면, vsnprintf()snprintf()널 (null)의 출력을 종료한다.

snprintf()함수에 상당한다 sprintf()버퍼의 크기 (S)로 지칭 상태 n 인수의 추가. n이 0이면 아무것도 기록되지 않고 s는 널 포인터가 될 수 있습니다. 그렇지 않으면 n-1st 이후의 출력 바이트는 배열에 기록되는 대신 폐기되고 실제로 배열에 기록 된 바이트의 끝에 널 바이트가 기록됩니다.

따라서 할당 할 버퍼의 크기를 알아야하는 경우 0 크기를 사용하고 널 포인터를 대상으로 사용할 수 있습니다. 내가 POSIX 페이지에 링크했지만, 이는 표준 C와 POSIX가 동일한 영역을 다루는 곳에서 차이가 발생하지 않는다고 명시 적으로 말합니다.

이 참조 페이지에 설명 된 기능은 ISO C 표준과 일치합니다. 여기에 설명 된 요구 사항과 ISO C 표준 간의 충돌은 의도하지 않은 것입니다. POSIX.1-2008의이 볼륨은 ISO C 표준을 따릅니다.

Microsoft 버전의 vsnprintf(). 버퍼에 충분한 공간이 없을 때 표준 C 버전과 확실히 다르게 작동합니다 (표준 함수가 필요한 길이를 반환하는 경우 -1을 반환합니다). 표준 C 버전이 수행하는 반면 Microsoft 버전 null이 오류 조건에서 출력을 종료한다는 것은 명확하지 않습니다.

TR 24731 안전 기능을 사용합니까?에 대한 답변도 참고하십시오 . ( 의 Microsoft 버전 은 MSDN 참조 vsprintf_s()) 및 안전하지 않은 C 표준 라이브러리 함수에 대한 안전한 대안은 Mac 솔루션입니까?


답변

일부 이전 버전의 SunOS는 snprintf로 이상한 일을했고 출력을 NUL로 종료하지 않았고 다른 사람들이하는 일과 일치하지 않는 반환 값을 가지고 있었을 수도 있지만 지난 10 년 동안 릴리스 된 모든 것은 C99를 수행했습니다. 말한다.


답변

모호성은 C 표준 자체에서 시작됩니다. C99와 C11은 모두 동일한 snprintf기능 설명을 갖습니다 . 다음은 C99의 설명입니다.

7.19.6.5 snprintf함수
개요
1 #include <stdio.h>
int snprintf(char * restrict s, size_t n, const char * restrict format, ...);

설명
2이 snprintf함수는 fprintf출력이 s스트림이 아닌 배열 (인수로 지정됨)에 기록된다는 점을 제외하고 와 동일 합니다. 경우 nIS는 제로, 아무것도 기록되지 않고, s널 포인터가 될 수있다. 그렇지 않으면 n-1st를 초과하는 출력 문자 는 배열에 기록되지 않고 버려지고 실제로 배열에 기록 된 문자의 끝에 널 문자가 기록됩니다. 겹치는 객체간에 복사가 발생하면 동작이 정의되지 않습니다.
반환
3 snprintf함수를 작성했다되었을 것입니다 문자 수를 반환n종료 널 문자를 계산하지 않거나 인코딩 오류가 발생한 경우 음수 값을 계산하지 않고 충분히 커야합니다. 따라서 반환 된 값이 음수가 아니고보다 작은 경우에만 null로 끝나는 출력이 완전히 기록되었습니다 n.

한편 으로 문장

그렇지 않으면 st를 초과하는 출력 문자n-1 는 배열에 기록되지 않고 버려지고 실제로 배열에 기록문자의 끝에 널 문자가 기록됩니다.

있다고
합니다 (경우 s3 자 길이의 배열을 포인트 등) n3, 다음 2 개 문자가 기록되고, 2 일 이상 문자가 삭제됩니다 ; 그런 다음 널 문자는 그 2 다음에 기록됩니다 (그리고 널 문자는 기록 된 세 번째 문자가됩니다) .

그리고 이것은 원래의 질문에 대한 답이라고 믿습니다.
답변 :
겹치는 개체간에 복사가 발생하면 동작이 정의되지 않습니다.
경우 n0 아무 것도 출력에 기록되지이다
의 부호화 에러가 발생하지 않으면, 그렇지 않으면, 출력은 항상 널 종료 ( 의 여부에 관계없이 출력 배열 여부에 출력 끼워 일부 문자가 출력되도록 폐기하지 다음 경우 배열이 오버플로되지 않음)
그렇지 않으면 (인코딩 오류가 발생하는 경우) 출력 이 null로 종료되지 않은 상태로 유지 될 수 있습니다 .

반면에
마지막 문장

따라서 반환 된 값이 음이 아니고 다음보다 작은 경우에만 null로 끝나는 출력이 완전히 기록되었습니다. n

모호함을 제공 합니다 (또는 내 영어가 충분하지 않음). 나는 적어도 두 가지 방법으로이 문장을 해석 할 수 있습니다 :
1. 출력은 null로 끝나는 경우와 반환 값은 음이 아닌 및 경우에만 미만의n 반환 값이 경우 것이있는 수단 ( 하지 미만 n, 즉 출력합니다 (를 포함하여 종료 null 문자)가 배열에 맞지 않으면 출력 이 null로 종료되지 않습니다 ).
2. 반환 된 값이 음이 아니고 보다 작은 경우에만 출력이 완료됩니다 (문자가 삭제되지 않음) .n


나는 위의 해석 1이 답변과 모순되고 오해와 긴 논의를 야기한다고 생각합니다. 이것이 snprintf함수를 설명하는 마지막 문장이 모호함을 제거하기 위해 변경이 필요한 이유입니다 (C 언어 표준에 대한 제안서를 작성하는 근거를 제공합니다). 링크에 대한 @ “Martin Ba”덕분에 http://en.cppreference.com/w/c/io/fprintf (참조 )
에서 모호하지 않은 표현의 예를 가져올 수 있습니다 . 4)

snprintf :이 기능의 설명을 변경하기위한 C 표준 제안 / 계획이 있습니까? ” 질문도 참조하십시오 .


답변