为什么换行符在导致它的字符串之前的位置没有被打印出来?

Why is the positioning of the newline character before the string leading to it not getting printed?

我是套接字编程的新手。我为接收器写了一个代码:

#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<string.h>
#include<unistd.h>

 int main()
{int ret= socket(AF_INET,SOCK_DGRAM,0);
  if (ret==-1)
   {printf("\nsocket creation fails");
    exit (0);}
  else
   printf("\nsocket creation succeeds");

 struct sockaddr_in sender;
 int port;
 printf("\nEnter port:");
 scanf("%d",&port);
 sender.sin_family= AF_INET;
 sender.sin_port=htons(port);
 sender.sin_addr.s_addr=INADDR_ANY;

 int ret1;
 ret1= bind(ret,(struct sockaddr *)&sender,sizeof(sender));

 if(ret1==-1)
 {printf("\nsocket binding fails");
  exit (0);}
 else
 printf("\nsocket binding succeeds");

 struct sockaddr_in receiver;
 char str[15]; 
 int addrlen=sizeof(receiver);

 while(1)
 {int rec=recvfrom(ret,str,sizeof(str),0,(struct sockaddr*)&receiver,&addrlen);
  printf("\nreceived");
  str[rec]='[=10=]';
  if(strcmp(str,"exit")==0)
  break;

  if (rec==-1)
  {printf("\nrecvfrom fails");
  exit (0);}

  else
  {printf("\nrecv succeeds");
   printf("\n%s",str);}
  }

  close(ret);
  return 0;
  }

此代码的输出在下一行打印 received 然后 recv succeeds,之后光标转到下一行但不打印 str。然而,在 while 的下一次迭代中,旧的 str 值在 receivedrecv succeeds 之前打印。这个问题在我使用的时候解决了 printf("%s\n",str) 而不是 printf("\n%s",str)。为什么会这样?

标准输出流 stdout 在定向到终端时通常是行缓冲的。根据 C 2018 7.21.3 3:

… When a stream is line buffered, characters are intended to be transmitted to or from the host environment as a block when a new-line character is encountered. Furthermore, characters are intended to be transmitted as a block to the host environment when a buffer is filled, when input is requested on an unbuffered stream, or when input is requested on a line buffered stream that requires the transmission of characters from the host environment…

因此,new-line 字符之后的字符保留在缓冲区中(在计算机内存中,不显示在输出设备上)直到写入 new-line 字符,或者您请求输入(如在关联的输入流上使用 scanf),或者您明确请求刷新缓冲区,或者写入的内容太多以至于缓冲区已满。

因此,在开头使用 new-line 个字符编写 printf 语句是不好的做法,例如 "\nrecv succeeds"。 C 设计用于在常见应用程序的行尾具有 new-line 个字符的输出,例如 "recv succeeds\n".