Angrave System Programming/Learning C
Text Input And Output(1)
몰랑&봉봉
2019. 1. 8. 15:41
Printing to Streams
How do I print string, ints, chars to the standard output stream?
printf를 사용하면 가능합니다. 첫 번째 파라미터는 출력될 데이터의 자리를 표시한 형식 문자열입니다. c string pointer를 위한 형식 지정자는 %s입니다. 이 형식 지정자는 c string이 Null character를 만나 끝날 때까지 출력합니다. integer를 출력하기 위한 형식 지정자는 %d이고, 메모리 주소를 출력하기 위한 형식 지정자는 %p입니다.
다음은 실제로 출력하는 코드의 예입니다.
char *name = ... ; int score = ...; printf("Hello %s, your result is %d\n", name, score); printf("Debug: The string and int are stored at: %p and %p\n", name, &score ); // name already is a char pointer and points to the start of the array. // We need "&" to get the address of the int variable
기본적으로 printf는 write가 호출되기 전까지 아무것도 출력하지 않습니다. printf에서 write가 호출되는 경우는 buffer가 가득 차거나 newline이 출력되는 경우입니다.
How else can I print strings and single characters?
%s와 같은 형식지정자를 이용하지 않고 string을 출력하려면 puts와 같은 함수를 사용해 출력할 수 있습니다.
한 문자만 출력하고 싶다면 putchar를 이용해 하나의 문자만 출력이 가능합니다.
How do I print to other file streams?
standard out stream이 아닌 다른 file stream에 출력하고 싶다면 fprintf를 사용합니다.
fprintf의 사용 예는 다음과 같습니다.
fprintf( _file_ , "Hello %s, score: %d", name, score);
위와 같이 사용하면 _file이라는 stream에 다음 인자를 출력하게 됩니다.
이 때 _file은 stdout, stderr, 또는 fopen이나 fdopen으로 반환된 FILE pointer입니다.
Can I use file descriptor?
물론 file stream이 아닌 file descriptor도 사용이 가능합니다.
이 때 사용하는 함수는 dprintf입니다.
dprintf의 원형은 다음과 같습니다
dprintf(int fd, char* format_string, ...);
stream은 buffer가 일어날 수 있으므로 data가 file descriptor에 써지는 것을 보장해줄 필요가 있습니다.
(?? - 질문 - stream 버퍼가 일어나는 것이 fd에 써지는 것을 보장해줘야 하는 이유??어떻게 해야하나??)
How do I print data into a C string?
data를 C string으로 변환해 주기 위해서는 sprintf나, 보안이 강화된 snprintf를 사용합니다.
snprintf는 첫 번째는 C string으로 변환해 저장할 문자열의 배열, 두 번째는 배열의 길이, 세번째는 그 배열에 문자열으로 저장할 내용을 적습니다.
사용 예는 다음과 같습니다.
char result[200]; int len = snprintf(result, sizeof(result), "%s:%d", name, score);
위와 같은 코드에서 result에는 name:score라는 문자열이 저장되게 됩니다.
예를 들어 name이 JMJUNG이고, score가 100 이라면
JMJUNG:100
이라는 문자열이 result에 저장되게 됩니다.
result의 길이가 내용을 담기에 충분한 길이라면 snprintf로 반환되는 값인 len은 result에 쓰여진 문자열의 길이입니다. 이 때 이 문자열의 길이에는 null character가 포함되지 않습니다.
즉 위와 같은 경우 JMJUNG:100의 strlen값인 10이 반환되게 됩니다.
만약 길이가 충분하지 않을 경우에는 모든 문자열이 다 써지는 것이 아니라 입력받은 길이에 맨 뒤에 null character를 포함시켜 그 앞까지만 문자열로 저장하게 됩니다.
아래의 코드를 통해 살펴봅시다.
char x[5]; int size = snprintf(x, 5, "%s%s%s", "12", "34", "56"); // writes "1234" + null printf("%d\n", size); // output 6
위의 코드에서 보면 x는 5바이트만 주어져 있는데, snprint로 5바이트만 썼을 때 인자로는 6바이트, 즉 null character를 포함해 7바이트를 인자로 넘겨주고 있습니다.
하지만 이때 x에 저장되는 문자열은 "1234\0"로 null character를 포함해 5바이트만이 쓰이게 됩니다.
하지만 반환되는 값인 size는 뒤에 인자로 넘겨준 문자열의 strlen, 즉 "123456"의 길이가 됩니다.
즉 size를 출력하면 6이라는 값이 출력됩니다.
이와 같은 경우 snprintf의 반환값은 snprintf로 x에 쓰여진 문자열의 길이와 다르므로 주의가 필요합니다.
What if I really really want printf to call write without a newline?
printf는 항상 write를 call하지 않습니다. (전에 나왔듯이, write는 system call이고 printf는 library call이므로 system call은 overhead가 크기 때문에) printf에서는 내부 buffer를 가지고 있고 그 buffer가 가득 차거나 new line을 출력할 때 write를 호출하게 됩니다.
하지만 이렇게 new line을 호출하지 않고 화면에 출력하고 싶다면 fflush 함수를 사용해야 합니다.
int main(){ fprintf(stdout, "Hello World"); fflush(stdout); return 0; }
위의 예제처럼 Hello World를 새로운 줄 입력 없이 출력하고 싶다면 fflush를 이용하면 됩니다.
(gcc에선 fflush 호출 없이 return 시 write가 되는 것 같습니다.-- 확인 필요 (fflush 없이 return해주면 Hello World가 new line없이 출력))
How is perror helpful?
방금 호출한 함수가 fail했다고 가정해봅시다. 이 때 perror 함수는 stderr에 perror안에 parameter와 failing return code를 출력합니다.
failing return code는 man page를 통해 확인할 수 있습니다. 다음은 perror를 이용한 예를 보여주고 있습니다.
int main(){ int ret = open("IDoNotExist.txt", O_RDONLY); if(ret < 0){ perror("Opening IDoNotExist:"); } //... return 0; }
위와 같은 코드를 작성하면 open에 실패했을 때 error를 출력할 수 있습니다.