delay 함수에서 3초 뒤에 출력하라고 했으니 3초 뒤에 출력되는 것은 당연합니다.
size 크기가 너무 작으면 내부적으로 할당된 최소 크기의 버퍼가 이용되는 것이고, 이는 컴파일러 구현체에 따라 다를 것입니다.
https://docs.microsoft.com/ko-kr/cpp/c-runtime-library/reference/setvbuf?view=msvc-160
size
버퍼 크기(바이트)입니다. 허용 범위: 2 <= size <= INT_MAX (2147483647). 내부적으로 크기 에 대해 제공 되는 값은 가장 가까운 2의 배수로 반올림 됩니다.
Visual C++에서는 허용 범위를 저렇게 제시하고 있지만, size를 2바이트로 적용해도 12바이트가 최소로 적용된 것으로 보입니다.
int main()
{
char* buf = malloc(1024);
memset(buf, 0, 1024);
setvbuf(stdout, buf, _IOFBF, 6); // 출력 버퍼의 크기를 10으로 설정
printf("Hello, world!\n");
delay(3); // 3초간 기다림
return 0;
}
이와 같이 변경해서 테스트해보면 setvbuf에서 8바이트까지 설정했을 때는 8바이트까지 출력되는 것을 확인할 수 있지만, 6으로 지정하면 12바이트까지 출력되는 것을 확인할 수 있습니다.
size의 범위는 2 이상이라고 되어 있지만, 내부적으로는 동작이 저렇게 되는 것으로 보입니다.
_IOFBF이면 IO 입출력을 FBF, Fully Buffered로 처리하게 됩니다.
이 경우 바로 입출력을 처리하지 않고, 버퍼에 잠시 저장된 이후에 처리됩니다. 약간의 시간 지연이 발생합니다.
따라서 delay 함수가 없으면 문자열의 일부만 출력된 상태에서 나머지 버퍼는 비워지지 않고 프로그램이 종료되기 때문에 전체 문자열이 출력되지 않습니다.
버퍼 모드를 _IOLBF, _IONOBUF로 바꿔서 테스트해보면 됩니다. 다만, 일반적으로 사용하는 함수는 아니니 깊이 들어갈 필요는 없습니다. scanf를 연속해서 사용하면 문제가 발생하는 원인을 설명하기 위해 입출력 버퍼를 설명한 것입니다. scanf에서 %s를 연속으로 처리할 경우 엉망이 되는 것인데, 대다수 책에서는 이유를 설명하지 않고, %s 입력을 한 번만 처리하는 것으로 문제를 가리는 경우가 많습니다. 그렇다고 문제를 가리지 않고 설명하려면 setvbuf까지 설명해야 합니다.
요약하자면
최소 버퍼 크기는 컴파일러 구현체에 따라 다르다. 너무 작은 크기는 지정하지 말자.
버퍼링 모드에서는 일정 시간 동안 버퍼링을 하기 때문에 시간 지연이 있어야 프로그램 종료 전에 버퍼링이 끝나는 것을 보장할 수 있다. 그래서 시간 지연 코드를 넣은 것일 뿐이다.