The mycopy.cpp example demonstrated the most common character I/O functions and programming patterns. This section summarizes them for convenience and elaborates on their behavior when handling binary data and converting between characters and longer integer types.
Function
Description
Stream
Output
ostream& put(char c);
Writes one character or byte to the output stream, discarding bits in excess of a character when writing larger integers.
ofstream
ostream& operator<<
Writes or inserts data of various types and sizes, including characters or bytes, to the output stream.
ofstream
Input
int get();
Reads one character from the input stream and returns it as a non-negative integer. The function fills the integer's least significant bits with the character and the most significant bits with zeros.
ifstream
istream& get(char& c);
Reads one character from the input stream and passes it back through the reference parameter.
ifstream
streamsize gcount();
The "get count" function returns the number unformatted characters read by the last input operation. Unformatted characters include the full line-separator sequence (on systems using multi-character line separators). streamsize is a type alias suitable for storing size values. Programs typically use the function when performing block read operations, but it is usable with character input.
ifstream
ostream& operator>>
Reads or extracts data of various types and sizes, including characters, from the input stream.
ifstream
Character I/O summary.
The most frequently used character I/O functions. For additional details and more functions, please see:
int c;
while ((c = in.get()) != EOF)
{
// process c
out.put(c);
}
char c;
while (input.get(c))
{
// process c
out.put(c);
}
(a)
(b)
(c)
int c = in.get();
while (! in.eof())
{
// process the data
out.put(c);
c = in.get();
}
int c = in.get();
while (in)
{
// process the data
out.put(c);
c = in.get();
}
int c = in.get();
while (in.gcount() > 0)
{
// process c
out.put(c);
c = in.get();
}
(d)
(e)
(f)
Character I/O patterns.
The code fragments illustrate some patterns programmers frequently use to process files one character at a time. The problem the program solves and the programmer's preference determine the best pattern to complete the program. The figure highlights the input or read operations in pink and the output or write operations in light blue. The example illustrates the program output with the variable c, but it may be any value resulting from the processing. The patterns illustrated in the second row require two input operations because the test condition relies on state flags set by a failed read operation.
Opening streams with constructors or the open function.
This overloaded version of the get function reads one character from the input stream and returns it as an integer. Embedding the get function call in the while-loop control causes the read and assignment operations to run first, followed by the test for equality. The get returns the symbolic constant EOF when the stream reaches the end of the file.
This overloaded version of the get function reads a single character from the input stream and passes it back through the reference parameter. The overloaded operator bool returns true only if none of the error flags are set.
The eof function returns true when the read operations have reached the end of the file.
The overloaded operator bool returns true only if none of the error flags are set, providing the Boolean value needed to continue or end the loop.
A while-loop based on the gcount function. Programmers typically use gcount with block read operations, but it also works with character-sized reads, returning 1 if the read succeeds or 0 at the end of the file.
Binary Character Data
Each byte or non-wide character consists of 8-bits, allowing 28 = 256 possible patterns of 1s and 0s. C++ programs interpret the patterns as numbers in two ways: 0 - 255 or -128 - 127. The difference is how they interpret the most significant bit (MSB): Interpreting the MSB as part of the numberer's magnitude results in only non-negative values (0 - 255), while interpreting it as the sign bit, with 1 denoting negative values, allows positive, negative, and zero values (-128 - 127). The get(char&) function interprets the MSB as a sign bit, returning a signed character through its parameter. The int get() function includes the MSB with the number's magnitude, returning the input as a value ≥ 0. It returns EOF, typically -1, when it reaches the end of the file, unambiguously differentiating data from the EOF marker (see Figure 2(b) above).
put(char)2
Generated1
Binary3,4
Hexadecimal4
get(char)5
int get()6
-128
10000000
80
-128
128
-127
10000001
81
-127
129
-126
10000010
82
-126
130
. . .
-3
11111101
fd
-3
253
-2
11111110
fe
-2
254
-1
11111111
ff
-1
255
0
00000000
0
0
0
1
00000001
1
1
1
2
00000010
2
2
2
3
00000011
3
3
3
. . .
125
01111101
7d
125
125
126
01111110
7e
126
126
127
01111111
7f
127
127
Illustrating the put and get function.
The table illustrates the behavior of the put and get functions with negative and positive numeric values. The table data is adapted from the output of the bin.cpp program, assuming a little-endian processor. When the int get() function reads a byte with the sign bit set (highlighted in red), it returns the value as an unsigned integer ≥ 128, preventing a value of -1 stored in the file from being inadvertently interpreted as EOF.
Generated by a for-loop with an integer loop-control variable iterating from -128 to 127 inclusive.
When the put function's argument is an integer, it truncates the value, saving only the last eight bits.
The function printing the binary output converts characters to unsigned long integers, using sign extension to fill the additional bits. For brevity, the table only displays the last eight bits.