<linux> read()와 write()의 차이

awdxawdx101의 이미지

리눅스의 read()와 wirte()의 fd에 똑같이 1을 주었을 때, read()는 버퍼를 입력받은 후 출력을 하고, write()은 바로 출력을 해주네요. fd=1 은 stdout을 의미해서 출력을 해주는걸로 알고있는데, 제가 어디를 잘못 알고 있는 건가요?

아래는 제가 테스트용으로 작성한 코드입니다.

#include <stdio.h>
#include <unistd.h>
 
int main(void){
	char buff[256];
 
	printf("buff address = ");
	read(1, buff, 8);
 
	return 0;
}

#include <stdio.h>
#include <unistd.h>
 
int main(void){
	char buff[256];
 
	printf("buff address = ");
	write(1, buff, 8);
 
	return 0;
}
konan&#039;s life의 이미지

하신 의도는 알겠지만 틀렸습니다.

우선 stdout, stdin과 같이 입출력의 경우 입출력 버퍼를 가지고 있습니다.

해당 입출력 버퍼는 '\n' 과 같은 개행문자를 입력받아야 비워지고요.

즉 read의 경우 printf시 개행문자가 없어 버퍼에만 지금 담겨 있을겁니다.

그리고 출력 fd에 read를 하였으니 fd에 데이터가 들어올때가지 대기중인 상태겠군요.

그리고 엔터를 입력하셨을거 같은데 엔터를 입력했으니 출력되었을겁니다.

awdxawdx101의 이미지

#include <stdio.h>
#include <unistd.h>
 
int main(void){
        char str[10]="hello\n";
 
        read(1, str, 10);
 
        return 0;
}

그런데 위 코드처럼 처음부터 문자열에 개행문자 넣어주어도 똑같이 입력을 받고, 이번에는 출력조차 안됩니다..
프로그램을 실행시켰을 때 바로 "hello"가 출력되려면 어떻게 해야하나요?

kind boy의 이미지

우선 표준출력(stdout)의 경우 해당 내용을 파일로 리다이렉트 하지 않는 이상
read 함수로 읽을수 없습니다.

만약 버퍼의 내용을 출력하고 싶으시다면 출력함수(fprintf, printf)등으로 출력하시면 됩니다.

약간 개념의 혼동이 있으신것 같습니다.

아래 참고하시고 표준 입출력 개념 및 버퍼링에 대해 확인하세요.
https://stackoverflow.com/questions/34966914/is-it-possible-to-read-from-stdout
http://www.pixelbeat.org/programming/stdio_buffering/

kind boy의 이미지

코드 동작 설명

#include <stdio.h>
#include <unistd.h>
 
int main(void){
	char buff[256];
 
        // printf를 사용하여 buff address = 를 버퍼에 저장함 (개행문자가 없으니 버퍼링) 
	printf("buff address = ");
        // read 함수를 호출하였으나 표준출력 fd를 read하였으므로 표준입력으로 대기 (block)
	read(1, buff, 8);
        // 아마 쓰니는 엔터를 입력한듯 표준입력으로 입력받은 \n을 buffer에 저장
        // 프로그램 종료전 리소스 해제함으로 표준 출력 버퍼 fflush => 출력됨
	return 0;
}
kind boy의 이미지

#include <stdio.h>
#include <unistd.h>
 
int main(void){
	char buff[256];
        // 표준 출력버퍼에 해당 문자열 저장중 
	printf("buff address = ");
        // buff 데이터를 표준 출력함 (buff에 데이터가 없으므로 출력안됨)
	write(1, buff, 8);
        // 프로그램 종료시 리소스를 해제함으로 표준 출력 버퍼 fflush => 출력됨
	return 0;
}
ㄲㄱ의 이미지

read 함수는 표준 입력으로 입력을 받을 때 사용하는 함수입니다. 즉 키보드로부터 문자를 입력받습니다. 왜 자꾸 이상한 것을 시도하시는지요.

익명 사용자의 이미지

왜요? 재밌는 문제 아닌가요?

1은 분명 표준 출력에 대한 file descriptor여야 하는데, 왜 read를 시도했을 때 EBADF 등의 오류를 반환하지 않고 읽기에 성공할까요? 0으로는 read만, 1과 2로는 write만 가능할 줄 알았는데요.

방금 저도 ubuntu server에서 테스트해보니 실제로 그렇군요.

어째서 이런 일이 일어나는지 한번 살펴 보고 싶네요. 지금은 시간이 없어서 곤란합니다만..

디스크립터가 문제가 아니고요.의 이미지

read는 표준입력 즉 키보드나 파일로부터 입력을 받아야 하는데,
소스 내에 있는 문자열을 받으려 하니까 문제입니다. 내가 아는한
절대로 불가능 합니다.

익명 사용자의 이미지

Quote:
소스 내에 있는 문자열을 받으려 하니까

어디서요?

질문자의 원래 의도가 어떻든 간에, 제가 재밌다고 느끼는 부분은 우분투 리눅스에서 표준 출력 fd(1)에 대해 read를 호출했을 때 마치 표준 입력을 읽는 것처럼 동작한다는 겁니다.

뭔가 이치에 맞지 않는 듯한 이 동작은 아마도 특정 구현에서의 side effect인 것 같은데, 어째서 이런 게 가능한지 알아보고 싶군요. 안 그래도 유사 터미널의 동작 관련해서 찾아보고 공부 중입니다.

위에 소스 있잖아요.의 이미지

질문자가 위에 적어 놓은 소스입니다.

#include <stdio.h>
#include <unistd.h>
 
int main(void){
        char str[10]="hello\n";
 
        read(1, str, 10);
 
        return 0;
}
와우 설마 진짜의 이미지

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
이게 어떻게 코드내에 있는 문자열을 받는거에요...
C언어 기초부터 보시길...
질문자가 어떤의도든간에 코드내용대로 해석하면
fd가 1인 파일을 읽어 str에 10byte 만큼 읽는다 아닌가요?
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

kind boy의 이미지

사람에 따라 재밌는 문제일수 있죠 근데 위에분 말투가 쓸데없는거 한다고 하니깐
좀 거슬리네요ㅋㅋㅋㅋ
여기서 삽질안해본사람 있습니까? 삽질하면서 배우는거지

ㅋㅋㅋ의 이미지

님 말투도 상당히 거슬립니다.

ㅋㄷ의 이미지

사람마다 어떻게 받아들이냐에 따라 저도 거슬릴수 있죠.
그런데 왠지 삶에 불만이 많으신 분일것 같네요.

혹시 점치고 사시는 분의 이미지

그냥 욕을 하세요.

kind boy의 이미지

저도 하면서 한가지 신기한게 fd를 표준 출력으로 read 함수를 호출하니
표준 입력을 받더군요.. 왜인지는 한번 read 함수를 뜯어봐야 될 것 같네요.

ymir의 이미지

stdin 이나 stdout 은 모두 같은 파일(터미널)에 연결되어 있습니다.
0, 1, 2 모두 동일한 파일을 가리키고 있기 때문에..
read(1, ..); 하면, 일단 read 에서 block 해 있다가..
엔터치는 순간, 해당 터미널에 input 이 발생했으므로, read 가 리턴한 것입니다.

https://stackoverflow.com/questions/48443136/c-how-read-function-read-from-stderr

stdin 이나 stdout 은 특정 fd 를 특수한 용도로 사용하겠다고 정의한 것일 뿐..
fd 자체의 특성은, 다른 fd 와 동일하다고 보시면 될 것 같습니다.

첫 번째 프로그램을 실행만 시켜놓은 상태에서...
lsof -p $(pidof a.out) 또는 ls -1 /proc/$(pidof a.out)/fd 명령으로, fd 를 확인해 보세요.

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

kind boy의 이미지

감사합니다. /proc/[pid]/fd 를 ls로 확인하다 보니 링크를 못봤었네요.

확인해보니 같은 터미널에 링크 되어있으니 터미널에서 입력 스트림을 읽었겠네요.

테스트 해본 결과 그래도 입/출력 버퍼는 각각 가지고 있는걸로 보이고요

kind boy의 이미지

결론: read(1,..) 했을때
fd 0, 1, 2 모두 같은 터미널에 연결되어있어
표준입력을 받게된다. !

조두soon의 이미지

익명은 많지만 4명인듯..

익명 사용자의 이미지

모를 일이죠. 1명인지 2명인지 8명인지.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.