뭉근 : 느긋하게 타는 불

ifstream 64

프로그래밍2014. 9. 25. 02:40

2년 전 쯤에 대용량 파일(2GB 이상의 파일) 처리가 가능한 프로그램을 만들어야 했다. 32비트 시스템에서는 4바이트 크기의 파일 포인터를 사용하기에 이런 파일에 대해 입출력 작업을 할 때 윈도우 API를 제외한 일반적인 방법으로 처리하기가 힘들었다. 지금이야 윈도우 API의 강력함을 알고 있지만서도 그 때 당시 크로스컴파일에 심취해있었기 때문에 윈도우 API로 파일 처리하는 것은 내 자존심이 허락하지 않았다.

직접 알아본 파일 처리 방법은 64비트 환경에서 컴파일 그리고 _fseeki64 류의 함수를 사용, fstream을 8바이트 파일 포인터를 지원하게 일반화 프로그래밍을 하는 것이었다. 급한데로 _fseeki64 류의 함수를 사용하여 잘 처리하였지만 코딩에 미련이 안남을 수 있겠는가? 시간이 남을 때 64비트 파일 포인터를 지원하는 fstream을 만드는 방법을 찾아보았다. 아래는 fstream64를 지원하는 코드이다.

   

#ifdef WIN32

typedef int64_t streamoff64;

class streampos64
{
        typedef streampos64 _Myt;
        typedef _Mbstatet _Statetype;
public:
        streampos64(streamoff64 _Off = 0)
                : _Myoff(_Off), _Fpos(0), _Mystate(0)
                {        // construct with stream offset
                }

streampos64(_Statetype _State, fpos_t _Fileposition)
                : _Myoff(0), _Fpos(_Fileposition), _Mystate(_State)
                {        // construct with conversion state and C file position
                }

_Statetype state() const
                {        // return conversion state
                return (_Mystate);
                }

   

직접 코드를 가져다 사용하면 C4927 에러가 나는데… 이게 여간 신경 쓰이는게 아니다.

   

c:\program files (x86)\microsoft visual studio 10.0\vc\include\streambuf(424): warning C4927: illegal conversion; more than one user-defined conversion has been implicitly applied

1> while calling the constructor 'streampos64::streampos64(streamoff64)'

1> c:\~\streamutil.h(15) : see declaration of 'streampos64::streampos64'

1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\streambuf(423) : while compiling class template member function 'streampos64 std::basic_streambuf<_Elem,_Traits>::seekoff(unsigned __int64,std::ios_base::seekdir,std::ios_base::openmode)'

1> with

1> [

1> _Elem=char,

1> _Traits=char_traits64<char>

1> ]

1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\fstream(135) : see reference to class template instantiation 'std::basic_streambuf<_Elem,_Traits>' being compiled

1> with

1> [

1> _Elem=char,

1> _Traits=char_traits64<char>

1> ]

1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\fstream(889) : see reference to class template instantiation 'std::basic_filebuf<_Elem,_Traits>' being compiled

1> with

1> [

1> _Elem=char,

1> _Traits=char_traits64<char>

1> ]

1> c:\~~~~~\header.h(63) : see reference to class template instantiation 'std::basic_ifstream<_Elem,_Traits>' being compiled

(생략)

   

C4927 에러는 warning 1단계 에러로 무진장 잘나온다. 한국어 버전은 어떻게 나오는지 모르겠지만 해석해보면 네가 정의한 데이터에 대해 암묵적으로 데이터 변환이 일어났는데 이를 해결 안하면 어떤 문제가 생길 수도 있다는 것이다. 이걸 한번 해결해보는게 바로 이번 포스트의 내용이다.

CPP에서 템플릿을 사용하는 함수나 클래스는 컴파일 시간에 그 타입이 결정된다. VC는 이에 대한 로그를 스택 형식으로 보여주기 때문에 관련 로그를 살펴보기 위해서는 맨 아래부터 살펴보면 아래 15번째 줄의 코드 라인부터 컴파일이 일어났고 이에 대한 워닝이 떴다는 것을 알 수 있다.

   

   

다음은 basic_ifstream에서 발생하는데 typedef basic_filebuf<_Elem, _Traits> _Myfb에서 워닝이 발생한다. 내용은 _Filebuffer를 만드는데 여기서 워닝이 발생한다~ 그리고 이 변수는 basic_filebuf에 속해있다 이다.

   

   

   

이제 실제 워닝 발생 지점이다.

   

   

ifstream64은 다음과 같이 아래의 소스 코드에 나와있듯이 basic_ifstream에 출력 문자열의 형태와 관리 방법을 정의하는 객체인 _Traits를 새롭게 정의한다. 여기서 주목해야될 것은 바로 pos_type과 off_type이다.

   

template<typename Elem>

class char_traits64 : public std::char_traits<Elem>

{

public:

typedef Elem char_type;

typedef long int_type;

typedef streampos64 pos_type;

typedef streamoff64 off_type;

typedef _Mbstatet state_type;

};

   

typedef std::basic_ifstream<char, char_traits64<char> > ifstream64;

   

일반적으로 ifstream에서 사용되는 char_traits는 아래와 같이 streampos와 streamoff 를 사용한다. 여기서 사용되는 streampos는 fpos<_Mbstatet>이며 streamoff는 32비트 정수형이다. ( * 64비트 환경에서는 64비트 정수형이다. )

   

   

소스코드에서 streamoff64는 uint64_t로 64비트 정수형이다. streampos64는 fpos<_Mbstatet>를 64비트에 맞춰서 새롭게 정의를 했다. 워닝은 바로 이 부분에서 발생하는 것이다. streampos64를 다시 살펴보면 생성자 부분에서 워닝이 발생한다는 것을 알 수 있다. 그렇다면 생성자에서 왜 워닝이 발생하는건가?

   

   

seekoff 함수의 return 문을 보면 streampos(~)를 반환한다. 하지만 return 데이터 형식은 pos_type으로 컴파일시에는 streampos64로 결정된다. 바로 여기에서 컴파일러는 데이터 형식이 정수형으로 비슷하지만 클래스에서 어떻게 처리할지 모르기 때문에 암묵적으로 데이터 변환이 일어나고 있다고 말해주는 것이다.

   

   

이를 해결하는 방법은 streampos에 해당하는 새로운 생성자를 만들어주면 워닝이 금방 해결 된다.

   

public:

streampos64(streamoff64 _Off = 0)

: _Myoff(_Off), _Fpos(0), _Mystate(0)

{        // construct with stream offset

}

   

streampos64(std::streampos _Off)

: _Myoff(_Off), _Fpos(0), _Mystate(0)

{        // construct with stream offset

}

   

fstream64를 사용하면서 선언한 곳마다 warning이 20~30줄 떠버리면 무진장 신경쓰인다. 거기다 왠지 모르게 C4927 워닝은 무시도 안된다. 이상 마친다~

   

그런데 64비트 환경에서 32비트로 컴파일하면 파일 포인터는 32비트일까 64비트일까? -_-??? 흠..

   

ps. boost::filesystem::fstream 도 있네? 봐봐야겠다.

일반적으로 벡터의 원소를 지울 때 erase를 사용하는데 이게 for 문을 돌리면서(iterator++를 하면서) 조건에 맞을 때 삭제하는 코드를 짜면 erase 후 iterator 변수가 가볍게 크래쉬를 발생시켜주신다. 할당해제하고 나면 어떻게 되는지 VS 환경에서 디버거로 본적이 있는데 iterator 변수가 할당해제한 원소를 계속 가리키고 있었던 것으로 기억난다. 아무튼 깔끔하게 프로그래밍 할려면 아래처럼...


std::vector<int *> vIntegers;

// fill integers in the vector.

for(int i = 0; i < 100; i++) {

vIntegers.push_back(new int(i));

}


auto it = begin(vIntegers);

while(it != end(vIntegers)) {

if(**it % 2 == 0) {

printf("%d ", **it);

it++;

} else {

// delete allocated memory of 4bytes, integer size

delete *it;

// erase returns next iterator of removed iterator 

it = vIntegers.erase(it);

}

}


아니면 삭제하는 부분을 그대로 for 문으로 나둬도 괜찮다.

for(auto it = begin(vIntegers); it != end(vIntegers);) {

while(it != end(vIntegers)) {

if(**it % 2 == 0) {

printf("%d ", **it);

it++;

} else {

// delete allocated memory of 4bytes, integer size

delete *it;

// erase returns next iterator of removed iterator 

it = vIntegers.erase(it);

}

}

}


for 문이 내게는 한 줄에 많은 정보를 줘서 더 가독성이 있다.

'프로그래밍' 카테고리의 다른 글

드라이버 개발 삽질 #1  (0) 2015.03.12
ofstream 한글 출력 문제  (0) 2014.10.22
ifstream 64  (0) 2014.09.25
가상 함수 테스트  (0) 2014.07.05
최상위 윈도우 핸들로부터 모든 자식 윈도우 핸들 얻기  (0) 2014.03.27

Quiet - 내향적인 사람들을 위한 또는 이해하기 위한 도서

  모두 알고 지내던 시골 동네에서 ‘인격’을 중시하던 문화는 도시로 오면서 ‘성격’을 중시하는 문화로 바뀌었다. 이렇게 산업화 시대를 지나며 외향성은 우리 문화의 이상으로 자리 잡았다. 하지만 과연 외향성이 답일까? 내향적인 사람들은 반드시 성격을 고쳐야 하는가? 라는 주제로 후기를 써내려가는 것도 좋겠지만 이 답은 책에 있기에 나의 경험에 비추어 ‘내향적인 사람이 살아야 하는 방식’에 대해 쓴다.

  6년 전 나는 군대에서 살아남기 위해 외향의 가면을 썼다. 모두 처음 만나는 사람이었고 내향적이었던 나로서는 그들을 흉내 낼 수밖에 없었다. 더욱이 그들 사이에서는 소위 성격 좋다고 말하는 사람이 다른 사람의 인정도 받고 잘나갔기 때문에 나 또한 그들을 닮기 위해 더욱 노력했다. 하지만 군대에서 하루하루가 너무 피곤했다. 이 책을 읽기 전까지 나는 그 피곤이 정신적 피곤이 아닌 단순한 육체적 피곤이라 생각했다.

  외향적인 사람들과는 다르게 내향적인 사람들은 외부 자극에 대한 반응이 낮은 편이다. 외향적인 사람은 새로운 사람을 만나고, 스키를 타고, 높은 볼륨의 음악 등의 강렬한 자극을 즐기지만 내향적인 사람들은 가까운 친구와 차를 마시거나 책을 읽는 정도가 ‘딱 맞다’고 느낀다. 이런 반응성은 각 성격이 소모한 에너지를 충전하는 방법으로 이어진다. 내향적인 사람은 자신만의 공간에서 에너지를 회복하고 그 곳에서 벗어나는 순간부터 에너지를 소모한다. 반면에 외향적인 사람들은 사람들이 많은 공간에서 에너지를 얻는다.

순전히 외향적인 사람이나 순전히 내향적인 사람 같은 건 없다. 그런 사람은 정신병동에 들어가 있을 것이다. by 칼 융

  융이 말했듯이 성격은 복잡한 것이어서 어느 순간에서는 내향적인 사람도 외향적으로 변할 수 있다. 대부분의 내향적인 사람들은 핵심 목표가 생기면 자신의 기질을 뛰어넘어 외향적인 사람처럼 행동할 수 있다. 하지만 이런 가면을 쓰는 행위는 일정 시간만 지속하되 나머지 시간은 반드시 자신의 모습 그대로 지낼 수 있어야 한다. 감정을 다스리고 바꾸려고 할 때 들어가는 ‘감정 노동’은 절대 가벼운 게 아니기 때문이다.

  가면을 쓰고 회복 환경 없이 지속되면 내향적인 사람은 어떻게 될까? 처음엔 정신적으로 탈진하게 되고 점점 신체적으로 탈진하게 된다. 이게 바로 내가 군대에서 뿐만 아니라 사회에 나와서도 피곤했던 이유이다. 내향적인 사람들은 양심적인 자세 때문에 자신이 감당할 수 있는 범위를 넘어선 만큼을 떠맡게 될 때, 평소라면 재미있을 일에도 흥미를 잃게 되며 건강도 나빠질지 모른다. 따라서 내향적인 사람들은 반드시 소모한 에너지를 자신만의 회복 공간에서 충전해야 한다.

  흔히들 내향적인 사람은 사교성이 부족하다고 걱정한다. 하지만 내향적이라도 사람하고 어울리는 걸 못하는 게 아니다. 사무적인 대화나 공적인 대화는 충분히 가능하다. 친구랑 노는 게 마냥 불편한 것도 아니다. 다만 혼자가 편하고 자기만의 공간이 필요한 것 뿐이다. 사교성이 부족한 문제는 외향적인 사람들에게서도 나타나는 부분이다.

  이런 내용 외에도 가면의 여부를 떠나 자신이 외향적인지 내향적인지 판단하는 방법, 내향적인 아이를 기르는 방법, 외향적인 남편과 내향적인 부인이 잘 지내는 방식 등 내향적인 사람들에게 좋은 내용이 나오니 읽어보면 참 좋을 것 같다.


ps. 내향성에 대한 만화 (http://sg-mh.com/viewer/2120999)

'생활' 카테고리의 다른 글

논문 영어 쓰기  (0) 2015.04.20
'배려'의 명언  (0) 2014.11.24
메모리 포렌식 도서 출간 예정  (0) 2014.04.11
다음팟 로컬 채팅무시 프로그램  (1) 2014.02.15
나니아 연대기  (0) 2013.02.12