<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko">
	<id>https://junhoahn.kr/junyoung/index.php?action=history&amp;feed=atom&amp;title=Robust_I%2FO_package</id>
	<title>Robust I/O package - 편집 역사</title>
	<link rel="self" type="application/atom+xml" href="https://junhoahn.kr/junyoung/index.php?action=history&amp;feed=atom&amp;title=Robust_I%2FO_package"/>
	<link rel="alternate" type="text/html" href="https://junhoahn.kr/junyoung/index.php?title=Robust_I/O_package&amp;action=history"/>
	<updated>2026-04-29T18:47:36Z</updated>
	<subtitle>이 문서의 편집 역사</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://junhoahn.kr/junyoung/index.php?title=Robust_I/O_package&amp;diff=2251&amp;oldid=prev</id>
		<title>Pinkgo: /* Buffered RIO Input Functions */</title>
		<link rel="alternate" type="text/html" href="https://junhoahn.kr/junyoung/index.php?title=Robust_I/O_package&amp;diff=2251&amp;oldid=prev"/>
		<updated>2025-04-22T06:57:44Z</updated>

		<summary type="html">&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;Buffered RIO Input Functions&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;ko&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← 이전 판&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2025년 4월 22일 (화) 06:57 판&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l71&quot;&gt;71번째 줄:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;71번째 줄:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;#include &amp;quot;csapp.h&amp;quot;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;#include &amp;quot;csapp.h&amp;quot;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;void rio_readinitb(rio_t *rp, int fd); //&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Returns: nothing&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;void rio_readinitb(rio_t *rp, int fd); //&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;반환값 없음&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;//Returns: number of bytes read if OK, 0 on EOF, −1 on error&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;//&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;읽은 바이트의 수 반환, EOF일때 0, 오류시 -1 반환&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;Returns: number of bytes read if OK, 0 on EOF, −1 on error&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n);&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n);&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l182&quot;&gt;182번째 줄:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;183번째 줄:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;위에서는 STDIN을 한줄 씩 읽어들인 다음, 이를 내부 버퍼에 저장한 후 STDOUT에 출력하는 간단한 예시이다. 이때 &amp;lt;code&amp;gt;rio_writen()&amp;lt;/code&amp;gt; 함수가 사용되었다.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;위에서는 STDIN을 한줄 씩 읽어들인 다음, 이를 내부 버퍼에 저장한 후 STDOUT에 출력하는 간단한 예시이다. 이때 &amp;lt;code&amp;gt;rio_writen()&amp;lt;/code&amp;gt; 함수가 사용되었다.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-deleted&quot;&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==각주==&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==각주==&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[분류:컴퓨터 시스템]]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[분류:컴퓨터 시스템]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key jy_wiki:diff:1.41:old-2250:rev-2251:php=table --&gt;
&lt;/table&gt;</summary>
		<author><name>Pinkgo</name></author>
	</entry>
	<entry>
		<id>https://junhoahn.kr/junyoung/index.php?title=Robust_I/O_package&amp;diff=2250&amp;oldid=prev</id>
		<title>Pinkgo: /* Unbuffered RIO Input and Output */</title>
		<link rel="alternate" type="text/html" href="https://junhoahn.kr/junyoung/index.php?title=Robust_I/O_package&amp;diff=2250&amp;oldid=prev"/>
		<updated>2025-04-22T06:37:00Z</updated>

		<summary type="html">&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;Unbuffered RIO Input and Output&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;ko&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← 이전 판&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2025년 4월 22일 (화) 06:37 판&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l11&quot;&gt;11번째 줄:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;11번째 줄:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;#include &amp;quot;csapp.h&amp;quot;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;#include &amp;quot;csapp.h&amp;quot;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;ssize_t rio_readn(int fd, void *usrbuf, size_t n);  &lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;ssize_t rio_readn(int fd, void *usrbuf, size_t n); //&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;파일에서 읽은 바이트의 숫자 반환&lt;/ins&gt;, &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;EOF일 때 &lt;/ins&gt;0, &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;오류일 때 -1 반환&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;//&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Returns: number of bytes transferred if OK&lt;/del&gt;, 0 &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;on EOF&lt;/del&gt;, &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;−1 on error&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;ssize_t rio_writen(int fd, void *usrbuf, size_t n); //&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;파일에 적은 바이트의 숫자를 반환&lt;/ins&gt;, &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;오류일 때 -1 반환&lt;/ins&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;ssize_t rio_writen(int fd, void *usrbuf, size_t n);&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;//&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;Returns: number of bytes transferred if OK&lt;/del&gt;, &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;−1 on error&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;code&amp;gt;rio_readn()&amp;lt;/code&amp;gt;함수는 디스크립터 fd의 현재 파일 위치로부터 최대 n 바이트를 버퍼 usrbuf로 전송한다. 이때 &amp;lt;code&amp;gt;rio_readn()&amp;lt;/code&amp;gt;함수는 EOF에 도달한 경우에만 short count를 반환할 수 있으며, 완전한 EOF인 경우&amp;lt;ref&amp;gt;읽기 작업을 시작하자마자 EOF인 경우에 해당한다.&amp;lt;/ref&amp;gt;에는 0을 반환한다. &amp;lt;code&amp;gt;rio_writen()&amp;lt;/code&amp;gt;함수는 버퍼 usrbuf에서 디스크립터 fd로 n 바이트를 전송한다. 이때 &amp;lt;code&amp;gt;rio_writen()&amp;lt;/code&amp;gt;함수는 절대 short counts를 반환하지 않는다. 이때 두 함수는 같은 디스크립터 내에서 임의로 교차하여 사용할 수 있다. 아래는 &amp;lt;code&amp;gt;rio_readn()&amp;lt;/code&amp;gt; 함수를 어떻게 구현하였는지 보여준다:&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;code&amp;gt;rio_readn()&amp;lt;/code&amp;gt;함수는 디스크립터 fd의 현재 파일 위치로부터 최대 n 바이트를 버퍼 usrbuf로 전송한다. 이때 &amp;lt;code&amp;gt;rio_readn()&amp;lt;/code&amp;gt;함수는 EOF에 도달한 경우에만 short count를 반환할 수 있으며, 완전한 EOF인 경우&amp;lt;ref&amp;gt;읽기 작업을 시작하자마자 EOF인 경우에 해당한다.&amp;lt;/ref&amp;gt;에는 0을 반환한다. &amp;lt;code&amp;gt;rio_writen()&amp;lt;/code&amp;gt;함수는 버퍼 usrbuf에서 디스크립터 fd로 n 바이트를 전송한다. 이때 &amp;lt;code&amp;gt;rio_writen()&amp;lt;/code&amp;gt;함수는 절대 short counts를 반환하지 않는다. 이때 두 함수는 같은 디스크립터 내에서 임의로 교차하여 사용할 수 있다. 아래는 &amp;lt;code&amp;gt;rio_readn()&amp;lt;/code&amp;gt; 함수를 어떻게 구현하였는지 보여준다:&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</summary>
		<author><name>Pinkgo</name></author>
	</entry>
	<entry>
		<id>https://junhoahn.kr/junyoung/index.php?title=Robust_I/O_package&amp;diff=2101&amp;oldid=prev</id>
		<title>Pinkgo: /* 각주 */</title>
		<link rel="alternate" type="text/html" href="https://junhoahn.kr/junyoung/index.php?title=Robust_I/O_package&amp;diff=2101&amp;oldid=prev"/>
		<updated>2025-04-17T17:23:35Z</updated>

		<summary type="html">&lt;p&gt;&lt;span class=&quot;autocomment&quot;&gt;각주&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;ko&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← 이전 판&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2025년 4월 17일 (목) 17:23 판&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l184&quot;&gt;184번째 줄:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;184번째 줄:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;위에서는 STDIN을 한줄 씩 읽어들인 다음, 이를 내부 버퍼에 저장한 후 STDOUT에 출력하는 간단한 예시이다. 이때 &amp;lt;code&amp;gt;rio_writen()&amp;lt;/code&amp;gt; 함수가 사용되었다.&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;위에서는 STDIN을 한줄 씩 읽어들인 다음, 이를 내부 버퍼에 저장한 후 STDOUT에 출력하는 간단한 예시이다. 이때 &amp;lt;code&amp;gt;rio_writen()&amp;lt;/code&amp;gt; 함수가 사용되었다.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;&lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&lt;/del&gt;&lt;/div&gt;&lt;/td&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-side-added&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==각주==&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;==각주==&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[분류:컴퓨터 시스템]]&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[분류:컴퓨터 시스템]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key jy_wiki:diff:1.41:old-2100:rev-2101:php=table --&gt;
&lt;/table&gt;</summary>
		<author><name>Pinkgo</name></author>
	</entry>
	<entry>
		<id>https://junhoahn.kr/junyoung/index.php?title=Robust_I/O_package&amp;diff=2100&amp;oldid=prev</id>
		<title>Pinkgo: 새 문서: 상위 문서: System-Level I/O  ==개요== &#039;&#039;&#039;RIO(Robust I/O)&#039;&#039;&#039;는 효율적이고 굳건한(robust) I/O를 제공하는 래퍼(wrapper) 함수들의 집합으로, 특히 short counts 문제에 취약한 응용 프로그램을 위해 사용된다. RIO는 두 가지 종류의 함수들을 제공한다. * Unbuffered 입출력 함수: 해당 함수들은 메모리와 파일 사이에 데이터를 직접 전송하며, 응용 프로그램 수준의 버퍼링(application-level b...</title>
		<link rel="alternate" type="text/html" href="https://junhoahn.kr/junyoung/index.php?title=Robust_I/O_package&amp;diff=2100&amp;oldid=prev"/>
		<updated>2025-04-17T17:23:23Z</updated>

		<summary type="html">&lt;p&gt;새 문서: 상위 문서: &lt;a href=&quot;/junyoung/index.php?title=System-Level_I/O&quot; title=&quot;System-Level I/O&quot;&gt;System-Level I/O&lt;/a&gt;  ==개요== &amp;#039;&amp;#039;&amp;#039;RIO(Robust I/O)&amp;#039;&amp;#039;&amp;#039;는 효율적이고 굳건한(robust) I/O를 제공하는 래퍼(wrapper) 함수들의 집합으로, 특히 short counts 문제에 취약한 응용 프로그램을 위해 사용된다. RIO는 두 가지 종류의 함수들을 제공한다. * Unbuffered 입출력 함수: 해당 함수들은 메모리와 파일 사이에 데이터를 직접 전송하며, 응용 프로그램 수준의 버퍼링(application-level b...&lt;/p&gt;
&lt;p&gt;&lt;b&gt;새 문서&lt;/b&gt;&lt;/p&gt;&lt;div&gt;상위 문서: [[System-Level I/O]]&lt;br /&gt;
&lt;br /&gt;
==개요==&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;RIO(Robust I/O)&amp;#039;&amp;#039;&amp;#039;는 효율적이고 굳건한(robust) I/O를 제공하는 래퍼(wrapper) 함수들의 집합으로, 특히 short counts 문제에 취약한 응용 프로그램을 위해 사용된다. RIO는 두 가지 종류의 함수들을 제공한다.&lt;br /&gt;
* Unbuffered 입출력 함수: 해당 함수들은 메모리와 파일 사이에 데이터를 직접 전송하며, 응용 프로그램 수준의 버퍼링(application-level buffering)은 없다. 주로 네트워크로부터 binary 데이터를 읽고 쓸때에 유용하다. &lt;br /&gt;
* Buffered 입력 함수: 해당 함수들은 표준 I/O 함수들(printf() 함수 등)이 제공하는 것과 유사하게 응용 프로그램 수준의 버퍼 내에 저장된(cached in an application- level buffer) binary 데이터들과 텍스트 라인들을 읽도록 한다. &lt;br /&gt;
** 표준 I/O 함수들과는 달리, RIO buffered 함수들은 &amp;#039;&amp;#039;&amp;#039;thread-safe&amp;#039;&amp;#039;&amp;#039;하며, 동일한 파일 디스크립터에 대해서 임의로 교차적으로(interleaved) 사용이 될 수 있다. 예를 들어 파일 디스크립터로부터 텍스트 라인 몇 줄을 읽고, 그 다음에 binary 데이터를 읽고, 다시 텍스트 라인을 읽는 것이 가능하다.&lt;br /&gt;
&lt;br /&gt;
===Unbuffered RIO Input and Output===&lt;br /&gt;
응용 프로그램은 &amp;lt;code&amp;gt;rio_readn()&amp;lt;/code&amp;gt;과 &amp;lt;code&amp;gt;rio_writen()&amp;lt;/code&amp;gt; 함수를 호출하여 메모리와 파일 사이에 데이터를 직접 전송할 수 있다.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;csapp.h&amp;quot;&lt;br /&gt;
ssize_t rio_readn(int fd, void *usrbuf, size_t n); &lt;br /&gt;
//Returns: number of bytes transferred if OK, 0 on EOF, −1 on error&lt;br /&gt;
ssize_t rio_writen(int fd, void *usrbuf, size_t n);&lt;br /&gt;
//Returns: number of bytes transferred if OK, −1 on error&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;rio_readn()&amp;lt;/code&amp;gt;함수는 디스크립터 fd의 현재 파일 위치로부터 최대 n 바이트를 버퍼 usrbuf로 전송한다. 이때 &amp;lt;code&amp;gt;rio_readn()&amp;lt;/code&amp;gt;함수는 EOF에 도달한 경우에만 short count를 반환할 수 있으며, 완전한 EOF인 경우&amp;lt;ref&amp;gt;읽기 작업을 시작하자마자 EOF인 경우에 해당한다.&amp;lt;/ref&amp;gt;에는 0을 반환한다. &amp;lt;code&amp;gt;rio_writen()&amp;lt;/code&amp;gt;함수는 버퍼 usrbuf에서 디스크립터 fd로 n 바이트를 전송한다. 이때 &amp;lt;code&amp;gt;rio_writen()&amp;lt;/code&amp;gt;함수는 절대 short counts를 반환하지 않는다. 이때 두 함수는 같은 디스크립터 내에서 임의로 교차하여 사용할 수 있다. 아래는 &amp;lt;code&amp;gt;rio_readn()&amp;lt;/code&amp;gt; 함수를 어떻게 구현하였는지 보여준다:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
ssize_t rio_readn(int fd, void *usrbuf, size_t n)&lt;br /&gt;
{&lt;br /&gt;
    size_t nleft = n; // 앞으로 읽어야할 byte의 수&lt;br /&gt;
    ssize_t nread; //지금까지 읽은 byte의 수&lt;br /&gt;
    char *bufp = usrbuf;&lt;br /&gt;
&lt;br /&gt;
    while (nleft &amp;gt; 0) {&lt;br /&gt;
        if ((nread = read(fd, bufp, nleft)) &amp;lt; 0) { /* read()는 한 번에 n 바이트를 못 읽을 수 있기 때문에 반복해서 읽음 */&lt;br /&gt;
            if (errno == EINTR)     /* 시그널 핸들러로 인해 인터럽트된 경우 */&lt;br /&gt;
                nread = 0;          /* 다시 read 호출 */&lt;br /&gt;
            else &lt;br /&gt;
                return -1;          /* 그 외 오류일 경우 에러 리턴 */&lt;br /&gt;
        } else if (nread == 0) break;              /* read() 함수가 0 반환시 EOF 도달로 간주 */&lt;br /&gt;
&lt;br /&gt;
        nleft -= nread;&lt;br /&gt;
        bufp += nread;&lt;br /&gt;
    }&lt;br /&gt;
    return (n - nleft);             /* 실제 읽은 바이트 수 리턴 (0 이상) */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
위 코드는 파일 디스크립터 fd로부터 정확히 n 바이트를 usrbuf로 읽어오는 작업을 수행한다. 이때 &amp;lt;code&amp;gt;read()&amp;lt;/code&amp;gt; 함수는 한번에 데이터를 원하는 만큼 읽어오지 못할 수 있으므로 반복하여 호출된다. 이때 시그널 인터럽트(EINTR)가 발생하면 읽기 작업을 재시도 하며, &amp;lt;code&amp;gt;read()&amp;lt;/code&amp;gt; 함수가 0을 반환하면 EOF 도달로 간주하고 종료한다. 이를 통해서 &amp;lt;code&amp;gt;rio_readn()&amp;lt;/code&amp;gt;함수는 실제로 읽은 바이트 수를 반환할 수 있다. 이때 &amp;lt;code&amp;gt;read()&amp;lt;/code&amp;gt;함수는 다음과 같은 원인으로 인해서 데이터를 한번에 원하는 만큼 읽지 못할 수 있다.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;커널 버퍼에 데이터가 부족한 경우&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
#* &amp;lt;code&amp;gt;read(fd, buf, n)&amp;lt;/code&amp;gt;을 요청했는데 커널에 n보다 적은 양만 준비돼 있으면, &amp;lt;code&amp;gt;read()&amp;lt;/code&amp;gt;는 그 준비된 양만큼만 읽고 바로 리턴한다.&lt;br /&gt;
# 시그널로 인한 인터럽트(errno == EINTR) 발생 시, &amp;lt;code&amp;gt;read()&amp;lt;/code&amp;gt;는 실패(-1)하고 중단된다.&lt;br /&gt;
# stream device의 특성으로 인해서 부분적인 읽기가 일상적인 경우도 있다.&lt;br /&gt;
#* 디스크 파일은 &amp;lt;code&amp;gt;read()&amp;lt;/code&amp;gt;함수를 사용시 보통 n바이트 다 읽힌다.&lt;br /&gt;
#* 하지만 네트워크 소켓, 파이프, 터미널 같은 &amp;#039;&amp;#039;&amp;#039;stream 기반 장치는 read가 준비된 만큼만 읽고 종료&amp;#039;&amp;#039;&amp;#039;하며, 이는 short counts의 원인이 된다.&lt;br /&gt;
위에서 1, 3번은 short counts의 가장 중요한 원인 중 하나이며, 다른 &amp;lt;code&amp;gt;read()&amp;lt;/code&amp;gt;함수가 충분하지 못한 양을 읽는 이유도 대부분 short counts와 관련이 있다. 하지만 &amp;lt;code&amp;gt;rio_readn()&amp;lt;/code&amp;gt; 함수의 구현 코드를 보면 알 수 있듯이 해당 함수는 short counts가 발생할 시 &amp;lt;code&amp;gt;read()&amp;lt;/code&amp;gt;함수를 다시 호출하여, short_counts로부터 자유로워지도록 한다. 아래는 &amp;lt;code&amp;gt;rio_readn()&amp;lt;/code&amp;gt;과 &amp;lt;code&amp;gt;rio_writen()&amp;lt;/code&amp;gt; 함수를 어떻게 구현하였는지 보여준다:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
ssize_t rio_writen(int fd, void *usrbuf, size_t n)&lt;br /&gt;
{&lt;br /&gt;
    size_t nleft = n; //버퍼에 저장해야할 바이트 수&lt;br /&gt;
    ssize_t nwritten; //버퍼에 저장한 바이트 수&lt;br /&gt;
    char *bufp = usrbuf;&lt;br /&gt;
&lt;br /&gt;
    while (nleft &amp;gt; 0) {&lt;br /&gt;
        if ((nwritten = write(fd, bufp, nleft)) &amp;lt;= 0) { /* write() 함수도 일부만 쓸 수 있으므로 반복하여 호출한다. */&lt;br /&gt;
            if (errno == EINTR)     /* 시그널 핸들러로 인해 인터럽트된 경우 */&lt;br /&gt;
                nwritten = 0;       /* 다시 write 호출 */&lt;br /&gt;
            else&lt;br /&gt;
                return -1;          /* 그 외 오류일 경우 에러 리턴 */&lt;br /&gt;
        }&lt;br /&gt;
        nleft -= nwritten;&lt;br /&gt;
        bufp += nwritten;&lt;br /&gt;
    }&lt;br /&gt;
    return n;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
위 코드는 사용자 버퍼 usrbuf의 내용을 fd에 정확히 n 바이트만큼 쓰는 작업을 수행한다. 이때 &amp;lt;code&amp;gt;write()&amp;lt;/code&amp;gt;함수가 일부분만 쓸 수 있기 때문에 반복하여 호출된다. 이때 시그널 인터럽트(EINTR)가 발생하면 쓰기 작업을 재시도한다. write는 EOF 개념이 없기 때문에 EOF의 경우는 고려하지 않는다.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;write()&amp;lt;/code&amp;gt;함수가 요청받은 바이트 수 만큼 한번에 쓰지 못하는 경우는 주로 시스템 버퍼가 다 찼을 때 발생한다. OS가 write 요청을 받으면 쓸 데이터를 커널 내부의 출력 버퍼에 저장한다. 하지만 네트워크 소켓이나 파이프의 출력 버퍼는 용량이 제한적이므로, 요청한 쓸 바이트 크기보다 현재 남아있는 출력 버퍼의 크기가 작은 경우, 해당 버퍼의 크기까지만 쓰고 리턴할 수 있다. 하지만 위 코드를 보면 알 수 있듯이, &amp;lt;code&amp;gt;rio_writen()&amp;lt;/code&amp;gt;함수는 이러한 문제에서 자유롭다. 즉, 특별한 에러가 발생하지 않는 이상, 요청받은 n 바이트를 모두 쓰는 것을 보장한다.&lt;br /&gt;
&lt;br /&gt;
===Buffered RIO Input Functions===&lt;br /&gt;
Buffered RIO 입력 함수들은 내부 메모리 버퍼에 부분적으로 캐시된 파일로부터 텍스트 라인과 binary 데이터를 효율적으로 읽는 함수들이다. 아래는 buffered RIO 입력 함수들이다:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;quot;csapp.h&amp;quot;&lt;br /&gt;
void rio_readinitb(rio_t *rp, int fd); //Returns: nothing&lt;br /&gt;
//Returns: number of bytes read if OK, 0 on EOF, −1 on error&lt;br /&gt;
ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);&lt;br /&gt;
ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;rio_readinitb(rio_t *rp, int fd)&amp;lt;/code&amp;gt; 함수에서 rp는 내부에 입력 버퍼와 상태 정보를 가지는 인자이다. Figure 2는 rio_t 구조체의 내부 구조를 보여준다. rio_t 구조체는 아래와 같은 3가지 필드가 존재한다:&lt;br /&gt;
* rio_buf: 버퍼 전체&lt;br /&gt;
* rio_bufptr: 현재 읽기 위치 (unread 시작점)&lt;br /&gt;
* rio_cnt: unread 바이트 수&lt;br /&gt;
또한 Figure 2에서 buffer에 속하지만, alread used도, unused도 아닌 공간은 아직 &amp;lt;code&amp;gt;read()&amp;lt;/code&amp;gt; 호출로 채워지지 않은 남은 버퍼 공간을 의미한다. 따라서, &amp;lt;code&amp;gt;rio_readinitb()&amp;lt;/code&amp;gt; 함수를 호출할 경우에는 내부 버퍼를 초기화하고 디스크립터인 fd와 해당 버퍼를 연결시키는 역할을 한다. 이는 &amp;lt;code&amp;gt;rio_readlineb&amp;lt;/code&amp;gt;나 &amp;lt;code&amp;gt;rio_readnb&amp;lt;/code&amp;gt; 함수를 사용하기 위해서는 어떤 디스크립터로부터 읽을 지와, 버퍼를 어디에 두어야 할지를 지정해야 하기 때문에 사용된다.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen)&amp;lt;/code&amp;gt; 함수는 다음 한 줄을 읽고, usrbuf에 이를 복사한다. 이때 문자열의 끝에는 항상 &amp;#039;\0&amp;#039; 문자를 붙여 C 문자열 처럼 usrbuf를 다룰 수 있도록 한다. 이때, 복사하는 바이트의 수는 최대 &amp;lt;code&amp;gt;maxlen-1&amp;lt;/code&amp;gt; 바이트로 제한되며, 그 이상의 줄은 잘리고, usrbuf의 끝 원소는 &amp;#039;\0&amp;#039;이 차지한다.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;rio_readnb(rio_t *rp, void *usrbuf, size_t n)&amp;lt;/code&amp;gt; 함수는 내부 버퍼에서 n 바이트까지 읽어서 usrbuf에 복사한다. 아래는 &amp;lt;code&amp;gt;rio_readinitb()&amp;lt;/code&amp;gt; 함수가 어떻게 구현되는지를 보여준다. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
void rio_readinitb(rio_t *rp, int fd)&lt;br /&gt;
{&lt;br /&gt;
    rp-&amp;gt;rio_fd = fd;&lt;br /&gt;
    rp-&amp;gt;rio_cnt = 0; //read()로 rio_buf에 데이터를 채우면 rio_cnt는 그 바이트 수만큼 설정된다.(내부 버퍼 내의 읽을 정보량)&lt;br /&gt;
    rp-&amp;gt;rio_bufptr = rp-&amp;gt;rio_buf; //내부 버퍼인 rio_buf 안에서, 다음에 읽을 위치를 가리킨다.(내부 버퍼 내의 현재 파일 위치)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
위 코드에서는 빈 읽기 버퍼를 설정하고, 파일 디스크립터를 해당 버퍼와 연결하는 역할을 한다. 또한 &amp;lt;code&amp;gt;rio_readnb()&amp;lt;/code&amp;gt;와 &amp;lt;code&amp;gt;rio_readnb()&amp;lt;/code&amp;gt; 함수가 어떻게 구현되는지 알기 위해서는 먼저 &amp;lt;code&amp;gt;rio_read()&amp;lt;/code&amp;gt; 함수가 어떻게 구현되는지에 대해서 먼저 알아야 한다. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n)&lt;br /&gt;
{&lt;br /&gt;
    int cnt;&lt;br /&gt;
    while (rp-&amp;gt;rio_cnt &amp;lt;= 0) { // &amp;quot;cnt &amp;lt;= 0&amp;quot;는 내부 버퍼에 읽을 데이터가 없다는 것을 의미&lt;br /&gt;
        rp-&amp;gt;rio_cnt = read(rp-&amp;gt;rio_fd, rp-&amp;gt;rio_buf,sizeof(rp-&amp;gt;rio_buf)); //read()로 디스크립터에서 rio_buf에 읽어옴&lt;br /&gt;
        if (rp-&amp;gt;rio_cnt &amp;lt; 0) { //read() 함수가 실패한 경우&lt;br /&gt;
            if (errno != EINTR) //시그널로 인터럽트된 경우 (EINTR) → 무시하고 다시 시도.&lt;br /&gt;
                return -1;&lt;br /&gt;
        }&lt;br /&gt;
        else if (rp-&amp;gt;rio_cnt == 0)  //read()가 0을 반환하면 → EOF, 더 이상 읽을 게 없음.&lt;br /&gt;
            return 0;&lt;br /&gt;
        else&lt;br /&gt;
            rp-&amp;gt;rio_bufptr = rp-&amp;gt;rio_buf; //성공적으로 읽었다면, 내부 포인터를 버퍼의 시작 위치로 초기화&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /* min(n, rp-&amp;gt;rio_cnt) 만큼 바이트들을 내부 버퍼에서 usrbuf로 옮긴다. */&lt;br /&gt;
    cnt = n;&lt;br /&gt;
    if (rp-&amp;gt;rio_cnt &amp;lt; n)&lt;br /&gt;
        cnt = rp-&amp;gt;rio_cnt;&lt;br /&gt;
    memcpy(usrbuf, rp-&amp;gt;rio_bufptr, cnt);&lt;br /&gt;
    rp-&amp;gt;rio_bufptr += cnt; //rp의 내부 버퍼의 현재 파일 위치를 복사한 바이트 수 만큼 이동시킨다.&lt;br /&gt;
    rp-&amp;gt;rio_cnt -= cnt; //rp의 내부 버퍼의 현재 파일 위치를 복사한 바이트 수 만큼 읽을 수 있는 바이트 수는 줄어든다.&lt;br /&gt;
    return cnt;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
위 함수를 보면 알 수 있듯이, &amp;lt;code&amp;gt;rio_read()&amp;lt;/code&amp;gt; 함수는 &amp;lt;code&amp;gt;read()&amp;lt;/code&amp;gt; 함수의 버퍼링된 버전이다. 따라서 해당 함수는 short counts를 반환할 수 있으며, 이는 오류가 아니다. 단지 해당 버퍼 내에 남아있는 바이트의 수(rio_cnt)가 요청받은 바이트 수보다 부족했음을 의미할 뿐이다. 응용 프로그램 입장에서는 &amp;lt;code&amp;gt;rio_read()&amp;lt;/code&amp;gt; 함수는 Linux의 &amp;lt;code&amp;gt;read()&amp;lt;/code&amp;gt; 함수와 동일한 의미를 가진다:&lt;br /&gt;
* 에러 시 -1을 반환하고 errno를 설정한다.&lt;br /&gt;
* EOF 시 0을 반환한다.&lt;br /&gt;
* 요청한 바이트 수가 버퍼에 남은 바이트 수를 초과할 경우에는 short counts를 반환한다.&lt;br /&gt;
두 함수가 유사하므로, &amp;lt;code&amp;gt;read&amp;lt;/code&amp;gt;로 대체하여 다양한 종류의 buffered 입력 함수들을 쉽게 구축할 수 있다. 아래는 &amp;lt;code&amp;gt;rio_readnb()&amp;lt;/code&amp;gt; 함수를 구현한 코드이다:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n)&lt;br /&gt;
{&lt;br /&gt;
    size_t nleft = n;&lt;br /&gt;
    ssize_t nread;&lt;br /&gt;
    char *bufp = usrbuf;&lt;br /&gt;
&lt;br /&gt;
    while (nleft &amp;gt; 0) {&lt;br /&gt;
        if ((nread = rio_read(rp, bufp, nleft)) &amp;lt; 0) return -1; /* errno set by read() */&lt;br /&gt;
        else if (nread == 0) break; /* EOF */&lt;br /&gt;
&lt;br /&gt;
        nleft -= nread;&lt;br /&gt;
        bufp += nread;&lt;br /&gt;
    }&lt;br /&gt;
    return (n - nleft);      /* Return &amp;gt;= 0 */&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
위 코드에서 알 수 있듯이, &amp;lt;code&amp;gt;rio_readnb()&amp;lt;/code&amp;gt; 함수는 구조상으로 &amp;lt;code&amp;gt;rio_readn()&amp;lt;/code&amp;gt; 함수와 동일하다. 다만 내부 버퍼에 파일의 내용을 저장한 뒤, 내부 버퍼에서 해당 내용을 끌어 쓸 뿐이다. 아래는 &amp;lt;code&amp;gt;rio_readlineb()&amp;lt;/code&amp;gt; 함수를 구현한 코드이다:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen)&lt;br /&gt;
{&lt;br /&gt;
    int n, rc;&lt;br /&gt;
    char c, *bufp = usrbuf;&lt;br /&gt;
&lt;br /&gt;
    for (n = 1; n &amp;lt; maxlen; n++) { //최대 maxlen-1 바이트 까지만 읽음&lt;br /&gt;
        if ((rc = rio_read(rp, &amp;amp;c, 1)) == 1) {&lt;br /&gt;
            *bufp++ = c;&lt;br /&gt;
            if (c == &amp;#039;\n&amp;#039;) { //개행 문자를 만나면 반복문 종료&lt;br /&gt;
                n++;&lt;br /&gt;
                break;&lt;br /&gt;
            }&lt;br /&gt;
        } else if (rc == 0) {         /* 예외 케이스 처리 */&lt;br /&gt;
            if (n == 1) return 0;     /* 완전한 EOF이므로 0을 반환함 */&lt;br /&gt;
            else break;               /* 몇몇 바이트를 읽었으나, 더 이상 읽을 데이터가 없음 */&lt;br /&gt;
        } else return -1;             /* Error */&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    *bufp = 0;    //usrbuf의 마지막 원소는 항상 &amp;#039;\0&amp;#039; 문자 사용&lt;br /&gt;
    return n - 1; //실제로 읽은 바이트의 수를 반환&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
마찬가지로 &amp;lt;code&amp;gt;rio_readlineb()&amp;lt;/code&amp;gt; 함수 또한 거의 동일한 메커니즘을 사용하는 것을 볼 수 있다. 다만 &amp;lt;code&amp;gt;read_nb()&amp;lt;/code&amp;gt; 함수와 마찬가지로, 내부 버퍼에 파일의 내용을 저장한 뒤, 내부 버퍼에서 해당 내용을 끌어 쓸 뿐이다.&lt;br /&gt;
&lt;br /&gt;
이때 궁금증이 들 수 있다. &amp;lt;code&amp;gt;rio_readn()&amp;lt;/code&amp;gt;과 &amp;lt;code&amp;gt;rio_readnb()&amp;lt;/code&amp;gt;는 사실상 같은 역할을 하는 함수이지만, 왜 같은 일을 하는 함수가 두 개나 존재하는가? 핵심적인 차이는 내부 버퍼를 사용하는지의 여부이다. &amp;lt;code&amp;gt;rio_read()&amp;lt;/code&amp;gt; 함수는 내부 버퍼를 사용하지 않고, 데이터를 읽고자 할 때마다 매번 &amp;lt;code&amp;gt;read()&amp;lt;/code&amp;gt; 함수를 호출한다. 따라서 해당 함수는 &amp;#039;&amp;#039;&amp;#039;stream에서 연속적으로 binary 데이터를 다룰 때 적함한 함수&amp;#039;&amp;#039;&amp;#039;이다.&amp;lt;br&amp;gt;&lt;br /&gt;
하지만, &amp;lt;code&amp;gt;rio_readbn()&amp;lt;/code&amp;gt; 함수는 내부 버퍼를 따로 가지고 있으며, 사용자가 원하는 만큼 꺼내 사용하는 함수이다. 따라서 &amp;lt;code&amp;gt;read()&amp;lt;/code&amp;gt; 함수는 오직 내부 버퍼를 채울 때만 수행된다. 따라서, 해당 함수는 &amp;#039;&amp;#039;&amp;#039;텍스트 라인과 binary 데이터가 동시에 사용된 파일을 다룰 때 유리하다. 또한 해당 함수는 caching을 사용하므로 더욱 빠르다는 장점이 있다. 이때, bufferd 입력 함수는 unbufferd 함수와는 섞어서 사용할 수 없다.&amp;#039;&amp;#039;&amp;#039; 그 이유는 buffered 함수가 내부 버퍼를 다룰 때 이미 fd를 이용하여 파일에 접근하므로, unbuffered 함수가 동작할 때는 현재 파일 위치가 예상치 못하게 변해 있을 수 있기 때문이다. 따라서 buffered 입력 함수를 사용하고자 할 때는 동일한 buffered 입력 함수와만 교차해서 사용하여야 한다. 아래 코드는 RIO 함수의 사용 예시를 보여준다.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
int main(int argc, char **argv)&lt;br /&gt;
{&lt;br /&gt;
    int n;&lt;br /&gt;
    rio_t rio;&lt;br /&gt;
    char buf[MAXLINE];&lt;br /&gt;
&lt;br /&gt;
    Rio_readinitb(&amp;amp;rio, STDIN_FILENO);&lt;br /&gt;
    while ((n = Rio_readlineb(&amp;amp;rio, buf, MAXLINE)) != 0)&lt;br /&gt;
        Rio_writen(STDOUT_FILENO, buf, n);&lt;br /&gt;
    exit(0);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
위에서는 STDIN을 한줄 씩 읽어들인 다음, 이를 내부 버퍼에 저장한 후 STDOUT에 출력하는 간단한 예시이다. 이때 &amp;lt;code&amp;gt;rio_writen()&amp;lt;/code&amp;gt; 함수가 사용되었다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==각주==&lt;br /&gt;
[[분류:컴퓨터 시스템]]&lt;/div&gt;</summary>
		<author><name>Pinkgo</name></author>
	</entry>
</feed>