훈, IT 공부/C,C++,MFC

문자입출력 메모리값으로 이해하기

IT훈이 2017. 12. 10.
반응형


표준 입출력 도구

Visual Studio 2013를 기본으로 진행합니다.

컴퓨터의 구조 조금 살펴보기(include)getchar,gets,scanf



 getchar()함수가 어떻게 메모리에 동작을 하는지에 대하여서 궁금증을 풀어 볼 것이다. 

그 전에 이론적인 부분을 보고 접근하자. 

메모리에 대하여 접근을 하기 위해서는 H/W에서부터 메모리에 이르기까지 어떻게접근이 되는지 틀을 기억하여야 한다. 




유저의 입출력이 발생 되었을 때


1. 우리가 키보드로 입력하는 값들은 커널Device Driver를 통하여 입력을 담당하게 된다.

2. 커널에서는 콘솔 매개체를 통하여 유저에게 입력값을 INPUT 하거나 OUTPUT한다.

3. INPUT된 값은 커널에 접근하기 위해 추상화된 FILE에게 전달된다.

4. FILE의 자체에는 Buffer 가 존재한다. 이 곳에 값이 쌓이게 되는 것이다.

5. Buffer의 값을 가져오는 것을(퍼올리는것) Buffered I/O 라고 한다.


!!!!입출력은 Kernel이 모두 담당한다. 유저가 입출력을 하는 것이 절대 아니다.!!!!



사실 우리는 하나다.. 가져오는 방식만 다를뿐


- getchar() : Buffer에서 한글자를 퍼올리는 방식

- gets() : 한줄을 퍼올리는 방식( \n혹은0 까지의 범위 ) 

- scanf() : 형식 문자의 규칙대로 가져오는 방식



getchar()함수의 메모리 접근 실습 #1 메모리 보기



1
2
3
4
5
6
#include <stdio.h>
int main(void)
{
    FILE *fp = stdin;
    return 0;
}



*fp 라는 변수 명을 이용하여 표준 입력 FILE 구조체에 대하여서 포인터를 생성한다.



표준입력 부분에 대하여서 기본 주소와 값들을 볼 수 있다.

( 자세히는 모르니 배운 부분만 작성해보았다. )


_bufsiz = 버퍼의 크기를 나타낸다.4096byte -> 환산하면 4KB

_base = 기본 주소를 나타낸다. 표준입력 buffer의 주소

_cnt = 읽어들일 값을 나타낸다. ( 버퍼에 값이 얼마가 있는지에 따라 다르다.)

_prt = 입출력 포인트를 가르킨다. 


getchar()함수의 메모리 접근 실습 #2 메모리 보기


기본적으로 어떻게 동작하는지 먼저 보고 넘어간다.


getchar(void)함수는 한 문자를 받는데, 

버퍼에 값이 있다면 버퍼의 값을 받아 리턴하고, 

없다면 사용자에게 입력을 요구한다.


putchar(출력할 문자상수)함수는 반드시 출력할 문자상수를 기술해야한다.


그러므로 

현재는 버퍼가 비어있기 때문에 사용자에게 입력을 요구한다. 

 

"""

버퍼가 비어있음을 어떻게 확인하느냐?

_base 주소를 보면 알 수있다. 0x777ec700 주소에 들어가보면

00 00 00 ... 으로 비어있음을 확인할 수 있다.

"""


Cori Life 라는 문자(배)열 10개의 길이를 입력한다.


왜 10개냐?? 마지만 개행문자까지 포함 하여야한다. ( \n )



버퍼 메모리에 값이 저장되었는 것을 확인 할 수 있다.


지금 한 것은 단순히 버퍼에 값을 입력하는 방식이다.

위에 보기와 같이 값이 저장된다는 것을 먼저 기억하자.



1
2
3
4
5
6
7
#include <stdio.h>
int main(void)
{
    FILE *fp = stdin;
    getchar();
    return 0;
}
cs
코드를 이렇게 입력하여도 상관없다는 것이다. 

변수를 활용하지 않았기 때문에


getchar()함수의 메모리 접근 실습 #3 메모리 보기

 이번에는 버퍼의 값을 변수에 담아서 출력해보는 실습을 진행 해보도록 하겠다.




사용자가 "Hello" 문자(배)열을 입력하여 버퍼에 값이 들어간 것을 볼 수 있다.


디버그 모드에서  cData = getchar(); 을 가르킨다. 


버퍼에 값이 있기 때문에 입출력 포인트가 가르키는 0x0f5cc701의 주소의 값 'e' 를 받아와 cData에 저장할 것이다.




한줄만 넘겨서 보면 


cData 에는 값 'e' 가 Copy&Overwrite하여 들어갔다.


*fp 표준입력 FILE의 값을 보면 값이 변한 것을 볼 수 있다.



다시 디버거에서 한줄만 넘겨본다면 


putchar(cData) 함수가 호출된다.

콘솔에 문자 'e' 를 출력한다. 




마지막 까지 디버거에서 실행을 시켜보았다.


콘솔에는 "el" 두개의 값이 출력되었고 


_ptr은 또 다음 주소를 가르켜고 있다.

_cnt는 0이 될때까지 계속해서 count 될 것이다.





오늘 알고 기억해야할 중요한 것을 종합해보면


1. 입출력은 커널이 담당한다. ( 유저 모드에서는 커널에 요청만 할 뿐 )

2. getchar() 함수는 버퍼에 가장먼저 접근한뒤 사용자에게 요청한다.




반응형

댓글