C and C++ full buffering row buffering and no buffering

  • 2020-11-18 06:22:38
  • OfStack

1. Introduction

In C/C++, I/O stream-based operations eventually call the system interfaces read() and write() to complete the I/O operation. To make programs run most efficiently, stream objects often provide buffers that reduce the number of calls to the system I/O interface.

There are three buffering modes, namely:
(1) Full buffering. The input or output buffer is filled and the actual I/O operation is performed. In other cases, such as forced refresh, process termination, the actual I/O operation is also performed.

For read operations, when the number of bytes read in is equal to the buffer size or the file has reached the end, or forced refresh, the actual I/O operation is performed to read the contents of the external file into the buffer. For write operations, when the buffer is filled or the flush is forced, the actual I/O operation is performed, and the buffer contents are written to the external file. Disk file operations are usually fully buffered.

(2) Row buffer. The input or output buffer encounters a newline character and does the actual I/O operation. Others are the same as full buffering.

(3) No buffer. There is no buffer, and the data is immediately read into memory or output to external files and devices. Standard error output stderr is bufferless, which ensures that error messages are fed back to users in a timely manner so that they can troubleshoot errors.

Three types of buffer macros are defined in the header file <stdio.h> .

缓冲类型
全缓冲 _IOFBF
行缓冲 _IOLBF
无缓冲 _IONBF

In the context of Linux, the following code is a good example of the difference between full buffering and line buffering.


#include <stdio.h>
#include <stdlib.h>

int glob=6; 
int main(int argc, char** argv)
{
  int var; 
  pid_t pid; 
  printf("a write to stdout\n"); 
  if(pid=fork()<0)
  { 
    printf("fork error"); 
  }
  else
  { 
    if(pid==0)
    { 
      glob++; 
      var++; 
    } 
    else
    { 
      sleep(2); 
    } 
  } 
  printf("pid=%d,glob=%d,var=%d\n",getpid(),glob,var); 
  exit(0); 
}

a. out is generated by default after successful compilation. The running results are as follows:

[

./a.out
a write to stdout
pid=4823,glob=7,var=4195873
pid=4824,glob=7,var=4195873

./a.out > temp.txt
cat temp.txt
a write to stdout
pid=4864,glob=7,var=4195873
a write to stdout
pid=4865,glob=7,var=4195873

]

It can be seen that printf is a line buffer when it outputs to standard output (the monitor), and when it encounters a newline character, it outputs the contents of the buffer to the monitor and clears the buffer. When the redirection command is used, standard output is redirected to a disk file. At this point, standard output becomes fully buffered. Instead of output when a newline is encountered, it is copied to a child process, with one copy each after the parent process finishes.

2. Buffer setting

(1) The buffer can be turned on or off using the functions setbuf() or setbuffer(). The parameter buf points to the buffer, indicating that the buffer is on, usually in full. Set the buf parameter to NULL to turn off buffering. Note that setbuffer() is a non-ES84en standard library function and is commonly found in Linux.

The buffer length of setbuf() is at least BUFSIZ(defined in ES90en.h), otherwise a buffer overflow may occur. setbuffer can specify the buffer size.


//@header:stdio.h
//@brief: Sets the specified buffer or closes the buffer 
//@param:stream: File pointer; buffer : Buffer address 
//@notice: Use the default buffer size BUFSIZ (in the stdio.h Defined) 
void setbuf ( FILE * stream, char * buffer );

//@notice: with setbuf , but the buffer size can be specified 
void setbuffer(FILE *stream, char *buf, size_t size);

Specify buffer as NULL and close the standard output buffer.


setbuf(stdout,NULL)

Specify a new buffer.


static char newBuffer[BUFSIZ];// At least, BUFSIZ (defined in stdio.h ), otherwise there is the possibility of buffer overflow 
setbuf(stdout,(char*)&newBuffer);

// Or specify the buffer size 
static char newBuffer[512];
setbuffer(stdout,(char*)&newBuffer,512);

(2) To change the buffering mode, use the function setvbuf().


//@header:stdio.h
//@brief: Change the buffer mode and set the buffer 
//@param:stream: File pointer; buf Buffer address; type : Buffer mode; size : Buffer size 
//@ret:0 Success, 0 failure 
int setvbuf(FILE *stream, char *buf, int type, unsigned size);

For example, with the flow buffer set to the row buffer, when setvbuf() is called, the buffer address is set to NULL and the buffer size is set to 0. Note that the premise is that there are buffers.


setvbuf(stream,NULL,_IOLBF,0); // Change buffering to row buffering 

// The above code is equivalent to 
setlinebuf(stream);       //for Linux

If the call to setvbuf specifies that the buffer size of size is greater than 0 and the buffer size of buf is NULL, setvbuf is assigned to apply for the buffer.


// The indirect application 1024 Byte full buffer 
setvbuf(stream,NULL,_IOFBF,1024);

That's C/C++ for full buffering, row buffering, and no buffering. For more information on C/C++ buffering, check out the other articles on this site!


Related articles: