널이 아닌 종료 문자열과 함께 printf 사용


107

null종료 되지 않은 문자열이 있고 정확한 크기를 알고 있다고 가정합니다 . 그러면 printfC에서 해당 문자열을 어떻게 인쇄 할 수 있습니까? 그런 방법이 떠오르지 만 지금은 알 수 없습니다 ...


9
에서 C컨텍스트, 모든 문자열이 null이 종료됩니다. null이없는 char 배열은 문자열이 아닙니다 ... char 배열입니다. :)
pmg


답변:


174

printf에는 가능성이 있으며 다음과 같습니다.

printf("%.*s", stringLength, pointerToString);

아무것도 복사 할 필요가 없으며 원래 문자열이나 버퍼를 수정할 필요가 없습니다.


10
어쨌든 그것은 위험하다, 누군가가 언젠가 %의이 캐릭터는 printf 것
pmod에

6
@Pmod : 버퍼가 외부 세계에 노출되지 않는 경우 반드시 그런 것은 아닙니다. 문자열의 일부만 인쇄하는 것도 매우 유용 합니다 (물론 null로 종료 될 수 있음). 이것이 실제로 작동하는 것을보고 싶다면 OpenSER / Kamailio SIP 프록시를 살펴보면이 기술로 인해 많은 것을 복사하지 않습니다 (sprintf도 사용).
DarkDust

6
또 다른 +1. 처럼 기본적인 것들에 대한 것들을 배울 때 나는 그것을 사랑 printf도 ~ 십년 후 ... :)
Hertzel 기네스

1
저에게는 API에서 null이 아닌 종료 문자열을 수신하고 (일부 Windows API가이 작업을 수행합니다!) '합리적인'방식으로 반환해야 할 때 매우 유용합니다. . 그래서 %에 긴 수명 * S (.! 또는 % * 또한 변환 유니 코드를 만들 것입니다 S <-> 당신을위한 단일 바이트))
FrizzTheSnail

3
@ user1424739 : 귀하의 경우 printf에는 최대 11 자 또는 NULL이 나올 때까지 인쇄합니다 . 귀하의 예에서 NULL이 먼저옵니다. 최대 길이를 지정해도 NULL이에 대한 "문자열 끝"의미를 잃지 않습니다 printf.
DarkDust

29

다음은 %.*s작동 방식과 지정 위치에 대한 설명입니다 .

printf 템플릿 문자열의 변환 사양은 일반적인 형식입니다.

% [ param-no $] flags width [ . precision ] type conversion

또는

% [ param-no $] flags width . * [ param-no $] type conversion

두 번째 형식은 인수 목록에서 정밀도를 가져 오는 것입니다.

'*'의 정밀도를 지정할 수도 있습니다. 이는 인수 목록의 다음 인수 (인쇄 할 실제 값 앞)가 정밀도로 사용됨을 의미합니다. 값은 int 여야하며 음수이면 무시됩니다.

—  glibc 매뉴얼의 출력 변환 구문

들어 %s문자열 형식, 정밀도는 특별한 의미가 있습니다 :

쓸 최대 문자 수를 나타 내기 위해 정밀도를 지정할 수 있습니다. 그렇지 않으면 종료 널 문자를 포함하지 않는 문자열의 문자가 출력 스트림에 기록됩니다.

—  기타 출력 변환 glibc 매뉴얼의

기타 유용한 변형 :

  • "%*.*s", maxlen, maxlen, val 오른쪽 정렬하고 앞에 공백을 삽입합니다.
  • "%-*.*s", maxlen, maxlen, val 왼쪽 정렬됩니다.

내가 올바르게 이해하면 다음은 출력을 채우면서도 여전히 문자열 오버플로를 방지합니까? "%-*.*s", padding, str_view.size(), str_view.data()
scx

20

stdout에 fwrite ()를 사용할 수 있습니다!

fwrite(your_string, sizeof(char), number_of_chars, stdout);

이렇게하면 첫 번째 문자 (number_of_chars 변수에 정의 된 숫자)를 파일,이 경우 stdout (표준 출력, 화면)에 출력합니다!


2
문자열과 0을 포함하는 긴 버퍼를 검사 할 때 매우 유용합니다!
Elist

13

printf("%.*s", length, string) 작동 안 할 것이다.

이것은 최대 길이 바이트 또는 널 바이트 중 먼저 오는 것을 인쇄하는 것을 의미합니다. null로 끝나지 않는 char 배열에 길이 전에 null 바이트가 포함되어 있으면 printf는 해당 바이트에서 중지되고 계속되지 않습니다.


4
그리고 이것은 OP의 질문에 대한 답변입니까?
Shahbaz 2011 년

12
null로 끝나지 않는 경우 null은 문자열에 포함 할 유효한 문자입니다. 이것은 여전히 ​​배열이 널 (null)로 끝나는 것으로 생각하고 하위 선택이되는 더 긴 배열로 취급합니다. 즉, 널이있는 문자열이 있으면 문제가 발생합니다.
lahwran

3
printf("%.5s", pointerToNonNullTerminatedString);

문자열 길이는 5입니다.


1
#include<string.h> 
int main()
{
/*suppose a string str which is not null terminated and n is its length*/
 int i;
 for(i=0;i<n;i++)
 {
 printf("%c",str[i]);
 }
 return 0;
}

코드를 편집했습니다. 다른 방법은 다음과 같습니다.

#include<stdio.h>
int main()
{
printf ("%.5s","fahaduddin");/*if 5 is the number of bytes to be printed and fahaduddin is the string.*/

return 0;

}

많은 불필요한 바이트 읽기 (대부분의 CPU에서 바이트가 워드로 정렬 된 주소에 있지 않은 경우 성능 저하를 동반 함)로 인해 성능이 매우 나쁘고 각 문자에 대해 형식화 구문 분석 및 적용이 수행됩니다. 그렇게하지 마십시오 :-) 해결책에 대한 내 대답을 참조하십시오.
DarkDust

@DarkDust : 병리학 적 기계 만이 단어 경계에 정렬되지 않은 바이트 읽기에 불이익을줍니다. 단어 경계에 정렬되지 않은 단어 읽기를 생각하고 있습니까? 아니면 고대 밉 쓰레기 같은 거?
R .. GitHub의 STOP 돕기 ICE

@R .. : x86이 뇌 손상을 입었다 고 생각한다면 절대적으로 동의합니다. x86은 단어로 정렬되지 않은 메모리를 읽고 쓰는 경우 패널티가 있기 때문입니다. ARM도 마찬가지입니다. 예를 들어이 질문 또는 이 질문을 참조하십시오 . 문제는 데이터가 메모리에서 단어 크기의 청크로 가져오고 올바른 바이트를 얻는 것이 또 다른 마이크로 작업이라는 것입니다 (올바르게 이해했다면). 큰 문제는 아니지만 거대한 루프에서 차이를 만들 수 있습니다.
DarkDust

@DarkDust : 바이트 읽기에 대해 완전히 잘못되었습니다. 가서 벤치 마크하지 그래? x86은 완전히 원자 바이트 작업을 수행하며 항상 사용했습니다. 단어 크기의 청크를 가져 오지 않습니다 (캐시 수준에서 훨씬 더 큰 청크를 가져오고 정렬은 관련이 없지만 이미 캐시 된 데이터에 대해 이야기하고 있습니다).
R .. GitHub의 STOP 돕기 ICE

@DarkDust : PS3는 SPU에서 정렬되지 않은 바이트 읽기 또는 쓰기를 지원하지 않습니다. 실제로 스칼라 유형도 지원하지 않으며 정렬되어야하는 벡터 만 있습니다. 컴파일러는 그것들을 에뮬레이트합니다. 그리고 많은 ARM 프로세서는 바이트 읽기 또는 쓰기를 지원하지 않고 워드 읽기 또는 쓰기 만 수행합니다.
Sylvain Defresne 2011 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.