본문 바로가기

프로그래밍/C

[function] dup2 함수 알아보기

📌 매뉴얼 (Linux)

더보기

NAME
       dup2 - duplicate a file descriptor
: 파일 디스크립터를 복제


SYNOPSIS
       #include <unistd.h>
       int dup2(int oldfd, int newfd);

DESCRIPTION
   dup2()
       The dup2() system call performs the same task as dup(), but instead of using  the  lowest-num‐
       bered  unused  file descriptor, it uses the file descriptor number specified in newfd.  If the
       file descriptor newfd was previously open, it is silently closed before being reused.

       The steps of closing and reusing the file descriptor newfd are performed atomically.  This  is
       important, because trying to implement equivalent functionality using close(2) and dup() would
       be subject to race conditions, whereby newfd might be reused between the two steps.  Such  re‐
       use  could happen because the main program is interrupted by a signal handler that allocates a
       file descriptor, or because a parallel thread allocates a file descriptor.

       Note the following points:
       *  If oldfd is not a valid file descriptor, then the call fails, and newfd is not closed.
       *  If oldfd is a valid file descriptor, and newfd has the same value  as  oldfd,  then  dup2()
          does nothing, and returns newfd.

: dup2() 시스템 호출은 dup()과 동일한 작업을 수행하지만 가장 낮은 번호의 미사용 파일 디스크립터를

사용하는 대신 newfd에 지정된 파일 디스크립터 번호를 사용합니다.

파일 디스크립터 newfd가 이전에 열려 있었다면 재사용되기 전에 자동으로 닫힙니다.

파일 디스크립터 newfd를 닫고 재사용하는 단계는 원자적으로 수행됩니다.

close(2)와 dup()을 사용하여 동등한 기능을 구현하려고 하면 경주 조건이 적용되어

두 단계 사이에 newfd가 재사용될 수 있기 때문에 중요합니다. 이러한 재사용은 파일 디스크립터를

할당하는 신호 처리기에 의해 메인 프로그램이 중단되거나 병렬 스레드가 파일 디스크립터를

할당하기 때문에 발생할 수 있습니다.


oldfd가 유효한 파일 설명자가 아니면 호출이 실패하고 newfd가 닫히지 않습니다.
oldfd가 유효한 파일 설명자이고 newfd가 oldfd와 동일한 값을 가지면 dup2()는

아무것도 하지 않고 newfd를 반환합니다.

 

RETURN VALUE
       On  success, these system calls return the new file descriptor.  On error, -1 is returned, and
       errno is set appropriately.

: 성공 시 이러한 시스템 호출은 새 파일 디스크립터를 반환합니다.

오류 시 -1이 반환되고 errno가 적절하게 설정됩니다.

📌 함수 설명

dup2 함수는 두번째 인자인 new fd의 값을 첫번째 인자인 old fd로 지정해주는 함수이다.

new fd가 이미 열려있다면, 해당 fd를 닫고 복제가 된다. 성공하면 새 fd를 반환하고, 오류이면 -1을 반환한다.

 

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

int main(void){
    int fd1, fd2;

    fd1=open("a.txt",O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
    printf("file open\n");
        
    fd2=dup2(fd1,STDOUT_FILENO);
    printf("fd1 :%d, fd2:%d\n", fd1, fd2);

    fd2=dup2(STDERR_FILENO,fd1);
    printf("fd1 :%d, fd2:%d\n", fd1, fd2);

    write(fd1,"stderr", 6);
    printf("printf를 썼지만 파일에 기록됨 \n");
}

이 코드는 open을 통해 연 fd1 (=3)이 존재하고, dup2 를 통해 기존 파일 디스크립터 1이 fd1이 보는 custom file을 

가리키도록 설정해준다. 그리고 fd1은 stderror (=2)를 가리키게 하여, fd가 1일때만 Custom file에 작성하도록 만들어준다.

 

코드를 처음부터 따라가보자면, fd1은 open을 통해 열게 된 현재 사용중이지 않은 가장 낮은 fd값인 3을 가지며 파일을 가리킨다.

그 상태에서는 printf를 하면 당연히 콘솔창에 출력이 되고, (1번째 그림)

 

dup2를 통해, STDOUT_FILENO(=1)이 fd1이 보고 있는 a.txt를 보도록 해준다. 그럼 fd2에 dup2의 결과가 저장되며

fd2는 1이 된다. 해당 상태에서 printf를 하게되면, printf는 fd 1이 가리키는 곳에 출력하므로 a.txt에 출력된다. (2번째 그림)

 

그리고 다시 dup2를 통해서, fd1(=3)이 STDERR_FILENO(=2)를 가리키도록 해주며, 해당 반환을 fd2에 넣어준다. (3번째 그림)

 

그럼 fd1에 write를 하게되면, STDERROR로 출력이 되는데, 겉보기엔 STDOUT과 동일하지만,

STDOUT은 버퍼를 사용해서 출력하고, STDERROR는 버퍼없이 출력하는 차이가 있다.

 

그 후, printf를 다시 사용해도, a.txt 파일에 계속 기록되는 것을 볼 수 있다.

 

결과 - std_output)

file open
stderr

 

결과 - a.txt)

fd1 :3, fd2:1
fd1 :3, fd2:3
printf를 썼지만 파일에 기록됨 

 

Recent Posts
Popular Posts
Recent Comments