为什么换行符在导致它的字符串之前的位置未得到打印?

问题描述

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

#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),(struct sockaddr*)&receiver,&addrlen);
  printf("\nreceived");
  str[rec]='\0';
  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在定向到终端时通常是行缓冲的。 Per C 2018 7.21.3 3:

...当流被行缓冲时,在遇到换行符时,字符打算作为块与主机环境进行传输。此外,当填充缓冲区,在无缓冲流上请求输入或在需要从主机环境传输字符的行缓冲流上请求输入时,字符打算作为一个块传输到主机环境。 …

因此,换行符之后的字符会保留在缓冲区中(在计算机内存中,不会显示在输出设备上),直到写入换行符或您请求输入(如scanf ),或者您明确要求刷新缓冲区,或者写入了太多内容以至于缓冲区已被填充。

因此,在开头使用换行字符(例如printf)来编写"\nrecv succeeds"语句是一种不好的做法。 C的设计目的是在输出中在常见应用程序的行尾添加换行符,例如"recv succeeds\n"