리눅스(Unix)에서 fflush(stdin) 사용시 발생하는 문제점.

 scanf 로 문자열을 받고 나면 공백으로 구분되서 남은 문자들이 아직 버퍼에 남아 있기 때문에…

fflush(stdin);

을 해줌으로써 버퍼를 비워주는 프로그래밍 기법이 있다.

 하지만 이것은 엄밀히 말하면 틀린것이다. 더 정확히 이야기하자면 VC 에서만(아마도..) 된다.

 사용자들의 편의를 위해 VC에서 확장의 개념으로 만든것이라 생각하면 이해가 쉬울 것이다.

 그렇다면 왜 이것이 안되는 것일까?

C FAQ 12.26을 보면 다음과 같은 말이 나온다.


C 언어 표준에 따르면,
fflush()는 output stream에 대해서만 동작합니다.
“flush”라는 정의가 buffering된 문자들을 쓰는 것을
완료시킨다는
12.15 것이므로 문자를 취소시키는 것(discard)과는 아무런 관계가 없습니다.
따라서
입력 스트림의 입력을 무시하는 기능과는 전혀 상관이 없습니다.

아직 읽지 않은 문자(unread characters)들을 stdio input stream에서
무시하는(discard) 표준 방법은 존재하지 않습니다.
어떤 컴파일러 회사들은 fflush(stdin)이 읽지 않은 문자들을 취소할 수
있도록 라이브러리를 제공하기도 하지만, 이식성이 뛰어난 프로그램을
만들려면 절대로 써서는 안되는 기능입니다.
(어떤 stdio 라이브러리는 fpurgefabort를 같은 기능으로
제공하기도 하지만, 마찬가지로 표준은 아닙니다.)
또한 input buffer를 flush하는 것이 꼭 해결책이라고 할 수도 없습니다.
왜냐하면
일반적으로 아직 읽히지 않은 입력은 OS-level input buffer에
존재하기 때문입니다.

Input을 flush할 방법이 필요하다면 (질문
[*]
19.1과
[*]
19.2에 나온 것처럼)
시스템 의존적인 방법을 찾아야 할 것입니다.
게다가 사용자가 매우 빠른 속도로 입력하고 있고, 여러분의 프로그램이
그 입력을 무시해버릴 수 있다는 것을 꼭 염두에 두어야 합니다.

또는 n이 나오기 전까지 문자를 읽어서 무시하거나,
curses에서 제공하는 루틴인 flushinp()를 쓰면 됩니다.
덧붙여 질문
[*]
19.1,
[*]
19.2도 참고하시기 바랍니다.

 즉 원래 fflush() 함수는 output stream에 대해서만 동작하는 함수이기 때문에 input stream에는 사용할 수 없는 것이고, 또 그런 함수는 존재하지 않는다는 것이다.(물론 표준이야기이다.)

 그렇다면 어떻게 해야할까?

(Language : c)
  1. scanf(“%d”, &a);
  2.  
  3. getchar();

 이런 식으로 바로 아래 라인에 다시 입력을 받는 함수를 호출에 버퍼에 남아있는 문자들을 비워주는 것도 하나의 좋은 보기가 될 수 있다.

gethostbyaddr 함수 호출시 널(NULL)값 리턴 문제…

 참으로 골치아픈 문제였다. 하지만 답은 간단했다.

 문제의 시작점은 gethostbyaddr() 함수를 호출하면서 시작됐다.

 210.125.213.93 (본인 블로그의 IP)주소. 어라???안돼네??

 무슨 문제일까…..
 211.115.77.213 (daum 의 IP 주소). 이것도 안되네??

사용자 삽입 이미지

 무슨 문제가 있나보다….나는 책에 나온 예제를 다시 하나하나 비교를 하면서 혹시 있을지 모를 미스타이핑을 찾아보았다.

 그런데…없.었.다.

 도대체 무엇이 문제일까…

 한참 고민을 하다가 디버깅을 해보았다.

 역시나….gethostbyaddr()함수를 호출하는 부분에서 에러가 발생했다.
 
 이 함수의 실행결과값이 바로 NULL 값이었던 것이다.

 그렇다면 왜 NULL 을 반환할까…계속 고민해보았다.

 혹시나 내가 인자값의 자료형을 잘못 전달한건 아닐까…함수사용을 제대로 하지 못한것은 아닐까…

 몇시간을 고민한 끝에 겨우 답을 얻을 수 있었다….

 IP 주소를 도메인 이름으로 바꾸는 과정은 역방향으로 조회를 하는 것이다.

 그런데 이 역방향 도메인 주소를 조회하기 위해서는 ISP에서 따로이 등록을 해줘야 한다.

 다시 설명을 하자면….

 daum.net == 211.115.77.213 이것은 조회가 가능하지만…(네임서버를 통해서)

 211.115.77.213 == daum.net 이것은 조회가 불가능할 수도 있다는 이야기이다.

 혹시나 싶어…학교 네임서버의 IP를 넣어 보았다.

사용자 삽입 이미지

 정상적으로 작동하는 것이 보인다 : )

 아마도 나와 비슷한 경험을 하는 사람들이 많으리라 생각된다.

 하지만 자신의 프로그램이 잘못된 것은 아니니 걱정말고 자신의 DNS서버의 IP를 넣어보거나 gethostbyname 함수를 통해 알아낸 정보중에 ns.*****.*****로 시작하는 주소의 IP를 넣어보길 바란다.

 그러면 아주 잘 동작하는 자신의 프로그램을 볼 수 있을 것이다.

 다음은 본인이 사용한 프로그램의 소스이다. 참고가 되길 바란다 : )

gethostbyaddr.c (Language : c)
  1. /***************************************************************************
  2. *            gethostbyaddr.c
  3. *
  4. *  Sat Jan  5 22:18:59 2008
  5. *  Copyright  2008  pchero21
  6. *  pchero21@gmail.com
  7. ****************************************************************************/
  8.  
  9. /*
  10. *  This program is free software; you can redistribute it and/or modify
  11. *  it under the terms of the GNU General Public License as published by
  12. *  the Free Software Foundation; either version 2 of the License, or
  13. *  (at your option) any later version.
  14. *
  15. *  This program is distributed in the hope that it will be useful,
  16. *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. *  GNU General Public License for more details.
  19. *
  20. *  You should have received a copy of the GNU General Public License
  21. *  along with this program; if not, write to the Free Software
  22. *  Foundation, Inc., 59 Temple Place – Suite 330, Boston, MA 02111-1307, USA.
  23. */
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <unistd.h>
  29. #include <arpa/inet.h>
  30. #include <netdb.h>
  31.  
  32.  
  33. void error_handling(char *message);
  34.  
  35. int main(int argc, char **argv)
  36. {
  37.     struct hostent *host;
  38.     struct sockaddr_in addr;
  39.     int i;
  40.    
  41.     if(argc != 2) {
  42.         printf(“Usage : %s <IP> n, argv[0]);
  43.         exit(1);
  44.     }
  45.    
  46.     memset(&addr, 0, sizeof(addr));
  47.     addr.sin_addr.s_addr = inet_addr(argv[1]);
  48.  
  49.     host = gethostbyaddr((char*)&(addr.sin_addr.s_addr), 4, AF_INET);
  50.     if(!host)
  51.         error_handling(“gethostbyaddr() error!”);
  52.    
  53.     printf(“Officially name : %s nn, host->h_name);
  54.    
  55.     puts(“Aliases———————-“);
  56.     for(i = 0; host->h_aliases[i]; i++) {
  57.         puts(host->h_aliases[i]);
  58.     }
  59.    
  60.     printf(“Address Type : %s n, host->h_addrtype == AF_INET ? “AF_INET” : “AF_INET6”);
  61.  
  62.     puts(“IP Address——————“);
  63.     for(i = 0; host->h_addr_list[i]; i++) {
  64.         puts(inet_ntoa(*(struct in_addr*)host->h_addr_list[i]));
  65.     }
  66.     return 0;
  67. }
  68.  
  69. void error_handling(char *message)
  70. {
  71.     fputs(message, stderr);
  72.     fputc(n, stderr);
  73.     exit(1);
  74. }
  75.