BLOG ARTICLE Programming | 3 ARTICLE FOUND

  1. 2010.07.26 시스템 시그널 캐치 충돌?
  2. 2007.12.12 제발 이런 삽질은..
  3. 2007.11.07 c언어에서 입력버퍼 비우기 10

얼마전에 타 벤더에서 제공받은 모듈을 우리쪽 프레임워크에 래핑작업을 했었다.. 아니 아직도 하는 중이다.
보통 라이브러리를 제공하면 archive(*.a)나 shared object(*.so)로 제공하는게 보통인데 오브젝트파일하나 덜렁 준다.
전화해서 archive나 so 제공안해주냐고 물어보니.. 자기네는 그거만 제공하고 그 라이브러리 쓰는 사이트 모두 같은걸 쓰니까 그냥 쓰랜다. 뭐 귀찮아도 빌드할때 한번 더 묶어주면 되니까 상관없는데 문제는 그 다음에 생겼다.

저쪽에서 제공받은 샘플은 잘 돌아가는데 내가 래핑한 api는 동작을 안한다. 내부적으로는 소켓 연결해서 통신하는 방식인데 fd를 아예 못받아 온다

return value = -111

찾아보니 connect refused
도대체 왜 그런지 알 수 없어 한참을 고민하다. 프레임워크 담당 하는 분께 물어보고 같이 원인을 찾아봤다.

새로배운 명령어 ...
truss
이걸로 실행파일을 실행시키면 실행시 커널레벨의 함수들이 콜되는 걸 볼 수 있다. 신기하다.....
truss는 aix에서 strace는 linux, hp는 tuse.. 나머지는 모르겠다.

암튼 저걸로 원인을 찾아보니 소켓에서 fd까지는 잘 받아왔는데 그 다음이 문제였다.
이것도 새로 안건데 우리쪽 미들웨어를 쓸때 다른 라이브러리와 묶을 때 .. 그러니까 벤더쪽에서 제공하는 라이브러리에서 안되는게 있었다. 몇몇개의 시그널들을 캐치하면 이쪽 미들웨어와 충돌이 발생한댄다.
어쨌건 확인해 보니 소켓으로 fd를 받아온 다음에 _sigaction로 14번 시그널(SIGALRM)을 캐치하고 있었다. 미들웨어가 쓰고 있어서 쓰면 안되는 놈중에 하나다.
그런데 fd를 잘 리턴받고(커널단에서) 시그널을 캐치했다고 fail이 나는건 왜인지 모르겠다.(공부 좀 해야것다.)

이걸 피하려면..
1. 저쪽에 우리 미들웨어하고 충돌안나는 라이브러리를 다시 달라고 하던가.
2. 우리쪽에서 데몬으로 짜던가..
3. 다른동네는 대부분 자바로 한대는데 자바로 하던가..

내 입장에서는 1번이 베스트인데.. 되려나 모르겠다
2번은 나중에 문제가 생길 소지가 많다.. 미들웨어에서 제공하는 데몬이면 모를까 생짜로 도는 데몬은 관리도 힘들다. 더구나 제공받은 라이브러리 자체가 그쪽 데몬에 접속하는 클라이언트 라이브러리인데.. 데몬에 접속하는 데몬을 짠다????
3. 우리쪽 업무프로세스를 이렇게 잡은 이상 저걸 바꾸면 그것도 머리아프다.
AND

qsort..

weight가 double이라면..

int compareDouble(const void *arg1, const void *arg2)
{
    return (weightDoc*)arg2)->weight - ((weightDoc*)arg1)->weight;
}

거기다 대부분 값들이 소수점 이하라면..

정렬이 될리가 없지 않은가..




int compareDouble(const void *arg1, const void *arg2)
{
    if( ((weightDoc*)arg1)->weight < ((weightDoc*)arg2)->weight )
        return 1;
    else if( ((weightDoc*)arg1)->weight > ((weightDoc*)arg2)->weight )
        return -1;
    else
        return 0;
}

뻘짓 하지 맙시다..
AND

c언어에서 가끔 발생하는 문제가 scanf로 입력받다가
입력버퍼가 다 비워지지 않아서 문자입력받는게 씹히는 경우가 생긴다.
c언어 공부하다보면 꼭 한번쯤은 겪어보는 문제
예를 들면

#include <stdio.h>

int main()
{
        char string[20];
        char c;

        scanf("%s", string);
        scanf("%c", &c);

        printf("%s\n", string);
        printf("!!%c!!\n", c);

        return 0;
}

실행 결과는?

문자열만 입력받아버리고 프로그램이 끝나버린다.

원인은
scanf("%s", string);
가 실행되고 나서 입력버퍼에는 개행문자가 그대로 남아있는 거다.

그래서
scanf("%c", &c);
를 실행하려고 보니 버퍼에 개행문자가 있어서 그걸 c에다 넣어버린거다.
정작 표준입력으로는 아무것도 입력안했는데
예전에 이걸 몰라서 개고생한거 생각하면..

해결방법은
입력버퍼를 비우면 된다.

어떻게?
        scanf("%s", string);

       scanf("%c", &c);
이 두 사이에 입력버퍼를 비워주는 뭔가를 해주면 된다.

1. 간단하게는 getchar(); 를 추가하는 걸로도 가능

2. fflush(stdin); 추가
그런데 이건 gcc에서 안돌아간다. 왜? 당연히 안된다. 표준 fflush함수는 출력버퍼를 비우는 녀석이다.
VC에서는 확장해서 사용하므로 동작하지만 gcc는 안된다.

3. tcflush(0, TCIFLUSH); 추가
0번 디스크립터를 비워라. 그런데 이는 유닉스 계열에서 터미널과 관련된 함수인 듯

4. rewind(stdio); 추가
rewind함수는 매개변수로 들어온 스트림을 초기화하는데 사용

5.
__fpurge(stdin);
이놈도 리눅스에서만 동작하고 표준은 아니다. stdio_ext.h 추가.

6.
fgets(string, sizeof(string), stdin);
문자열 입력을 scanf가 아니라 fgets로 받는다.
그러나 입력시 사이즈를 오버하면 똑같은 문제가 발생한다.
그리고 사이즈를 오버하지 않더라도 문자열 끝에 개행문자가 추가된다.

그래서 다음 줄에
string[strlen(string)-1] = '\0'; 로 강제로 널문자를 넣어준다.
개인적으로 제일 많이 사용하는 방식

7. scanf("%*c", c);
%*c는 입력은 받지만 저장은 안한다. 즉 비어있는 \n를 날려버린다.

8. scanf("%c", &c);를 scanf(" %c", &c); 로
%c 앞에 공백을 추가하면 white space를 구분자로 인식한다.


입력들이 간단하게 위와 같이 나온다면 위의 방법들 아무거나 사용해도 되지만
복잡한 입력에 입력버퍼에 뭔가 많이 남는다면
버퍼를 비우는 것이 근본적인 해결방법인듯 하다.



상황에 따라 적절히 골라쓰면 될 듯..

AND