Static duration means that the object or variable is allocated when the program starts and is deallocated when the program ends.

- MSDN


iTrans 버그 리포트 중에 아주 이상한 내용을 하나 들었다.

같은 자막을 두 번 변환하면  가 추가된다는 것…


제보해주신 분들과 연락을 해보니[각주:1] static으로 선언한 어떤 부분의 데이터가 깨지는 게 원인이었다.


bool CSami2Srt::convISO88591(LPCTSTR lp, TCHAR &tc, int &len)

{

  static LPCTSTR lpEntityNames[] = {

    _T("quot"),  _T("apos"),   _T("amp"),   _T("lt"),    _T("gt"),

    _T("nbsp"),  _T("iexcl"),  _T("cent"),  _T("pound"), _T("curren"),

    _T("yen"),   _T("brvbar"), _T("sect"),  _T("uml"),   _T("copy"), ...

  };


  static TCHAR tcEntityValues[] = {

    34,   39,   38,   60,   62,

    32,   161,  162,  163,  164,

    165,  166,  167,  168,  169, ...

  };

  

  static int lens[sizeof(lpEntityNames)/sizeof(lpEntityNames[0])];

  static bool first=true;

  if (first) {

    first = false;

    for (int i=0; i<sizeof(lpEntityNames)/sizeof(lpEntityNames[0]); i++) {

      lens[i] = _tcslen(lpEntityNames[i]);

    }

  }

}


문제를 일으킨 부분이 바로 이 쪽이다.

lens[]라는 배열은 lpEntityNames[] 각 값의 길이를 저장하기 위해 만든 static 배열이다.

그리고, 당연히 이 배열은 프로그램이 실행되자마자 할당되고, 프로그램 종료시 해제된다.

더불어, static인 first로 인해, 최초 실행때 한번만 초기화되고, 종료시까지 유지된다.


그런데, 가끔 이 부분이 여러번 실행되면 저 lens[]의 내용이 망가지는 것이다.


그래서 위 코드의 15-22 행을 아래와 같이 바꿔봤다.


  int lens[sizeof(lpEntityNames)/sizeof(lpEntityNames[0])];

  for (int i=0; i<sizeof(lpEntityNames)/sizeof(lpEntityNames[0]); i++) {

    lens[i] = _tcslen(lpEntityNames[i]);

  }


별로 크게 바뀐 건 없고, 그냥 매번 이 메쏘드가 호출될 때마다 다시 길이를 계산하는 걸로 바꾼 것.

그런데, 이렇게 바꾸자 아무런 문제가 발생하지 않는다.

근데, 이렇게 하면 불필요한 _tcslen()이 너무 많이 실행이 될 것 같다.


그래서, 최종적으로 아래와 같이 바꿨다.

그냥, 각 항목의 길이를 별도로 저장하는 것으로…


  static size_t nEntityLens[] = {

    4,  4,  3,  2,  2,

    4,  5,  4,  5,  6,

    3,  6,  4,  3,  4,...

  }


문제는 이렇게 해결을 했는데, 왜 처음의 방식에서 lens[]의 값이 바뀌었는지는 모르겠다.

내가 static의 개념을 잘 모르는 건가? OTL


  1. 아무리 해봐도 내 PC에선 재연이 안 됐음 [본문으로]
신고
  1. Favicon of http://b5.aurynj.net BlogIcon 어­리 2013.12.01 15:07 신고

    값이 static이라고 해도 접근하는 코드가 그 값의 initializer가 아니니 함수의 본체로 매번 실행되겠죠. lens의 타입클래스를 정의하셔서 초기화 구문을 그 안에 넣으면 해결될 거예요.

    • 차라리 매번 실행되면 문제가 없습니다.
      문제는, 실행은 제대로 한 번만 되지만, 이후에 내부의 값이 깨진다는 겁니다.

      어짜피 그냥 별도의 배열로 잡아버렸으니 이제 뭐 별 문제도 없을 겁니다.

      관심가져주셔서 고맙습니다. ㅠㅠ

    • Favicon of http://b5.aurynj.net BlogIcon 어­리 2014.01.04 19:16 신고

      아.. 헐.. 다시 보니 굉장히 골떄리는 문제였네요

  2. Favicon of http://minimonk.net BlogIcon 구차니 2013.12.26 11:01 신고

    음.. static이 어떤 용도로 쓰이는건가요?
    제가 아는 static은 global에서는 파일 내에서만 지역 변수이고
    함수 내에서는 정적변수로 scope 벗어 나도 계속 유지되는걸로 사용을 했는데요..

    아무튼 문득 드는 생각이 cpu 퍼포먼스로 인해서
    stelen이 thread safe하지 않아 생기는 문제가 아닐까 조심스레 추측을 해봅니다.

+ Recent posts