C++

error LNK2019: __imp_WSAStartup

  • 원인 : ws2_32.lib 를 링크하지 않아서 발생하는 문제
  • 해결 : ws2_32.lib 를 추가

 

relocation 0 has invalid symbol index 11

  • 원인 : 빈 cpp 파일을 링킹할 때 발생하는 에러
  • 해결 : 빈 cpp 파일 제거


Little Endian & Big Endian

  • struct 의 경우 variable의 bit order 변경 뿐 아니라 variable의 순서도 바뀌게 된다. 따라서 아래와 같이 little endian에서 작성된 struct는 big endian machine 에서 역순으로 기술되어야 한다.

     

 

AIX

  • 속도적인 이슈로 인하여 char로 선언한 경우 default로 unsigned char로 동작한다.  xlc Compile Option 중 하나인  -qchar=signed 를 사용하여 gcc등의 다른 컴파일러와 같이 signed char로 동작하게 바꿀 수 있다.
  • 아래와 같은 에러가 발생한 경우 runtime 라이브러리 버전이 문제일 수 있다. xlC runtime 버전을 6.0.0.0 에서 8.0.0.0 으로 업데이트 진행하면 해결될 수 있다.

    관련링크 : IBM developerworks

HP UX

  • memory allocation 시 64bit의 경우 8byte, 32bit의 경우 4byte 단위로 alignment 를 잘 맞추어서 할당해야 한다. 구조체 생성시에도 padding 용 변수를 두어 alignment를 맞춘다. 아래 메시지는 memory alignment가 맞지 않은 경우 발생한 에러메시지의 일부를 발췌한 것이다.

     
  • memory allocation 부분에서 segfault 가 발생한 경우
    • gdb example
    • 원인 : 하나의 프로세스가 할당 가능한 데이터 세그먼트 합계를 지정하는 kernel parameter 값(maxdsiz, maxdsiz_64bit)이 작아 프로그램이 더이상 메모리를 할당하지 못하고 죽음
      • kernel parameter 확인 방법

         
      • 실제 물리 메모리 사이즈 확인 방법 (How to check Physical memory in HP-UX)

         
    • 해결 : root 권한을 이용해 해당 kernel parameter 값을 증가시킨 후 (32비트 : 2G , 64비트 : 64G로 설정하였음)  재부팅


GCC

  • Fix LD_LIBRARY_PATH at compile time”-rpath <path>”    or “-Wl,-rpath,<path>”

     

General Tips

  • Check the dependency of dynamic library ( .so file )


본인이 접한 이번 에러의 케이스는 총 2가지


2가지 모두 라이브러리에 해당하는 모듈과 그걸 이용하는 바이너리 모듈 빌드시 빌드 옵션의 차이로 인해 발생하는 에러. 빌드 방식을 통일하거나, 바이너리 모듈 빌드시 차이를 포괄할 수 있는 옵션을 사용하면 된다. 


연관 빌드 옵션


  • Runtime Library 옵션 : /MTd /MD /MT 등등 ( 참조링크 )
  • DEBUG/RELEASE 옵션


하나는, 라이브러리에 해당하는 것을 DEBUG 모드로 빌드하고 그걸로 바이너리를 만드는 빌드시스템에서는 RELEASE로 해서 에러 발생. 이는 둘다 빌드 모드를 맞춤으로 해서 해결함.


다른 하나는 Runtime Library 사용에 대한 옵션 차이로 인해 발생한 에러. 이쪽도 빌드 옵션을 맞춰서 해결하였음. 참고로 재배포 패키지 버전간 차이로 인한 오동작을 줄이기 위해 /MTd로 일괄 사용하였다.

멀티플랫폼을 고려한 빌드 시스템을 고려할 때 윈도우 쪽에서 발생할 수 있는 이슈.


윈도우 컴파일러에서 c용 컴파일러로 돌려야 하는데 CPP용의 엄격한 룰체크 기반의 컴파일러로 돌아가서 그런다. 대부분의 경우에는 파일의 확장자를 보고 자동으로 동작하지만, 제대로 동작하지 않을 경우 명시적으로 C소스파일을 지정하는 옵션( /Tc 또는 /TC )을 넣어야 한다.

Building C++ Library ......... : no 
가 나온 경우 필수 라이브러리가 설치가 안되있거나 configure에서 인식을 못하는 경우 두가지가 있다.


필수라이브러리 목록은 여기( http://thrift.apache.org/docs/install )를 참고하면 된다.


BOOST library를 기본 경로에 설치하지 않고 자기계정의 특정 디렉토리에 설정한 경우


$BOOST_ROOT에 설치된 경로를 넣고 configure  실행시 --with-boost=$BOOST_ROOT 라고 입력하면 C++ libary가 잡히게 된다.

각 프로젝트 별로 "런타임 라이브러리" 형식을 모두 맞춰야 한다. 한가지라도 틀리게 되면 연관된 모든 라이브러리가 링킹 에러를 내뱉게 된다.


Visual C++ : 솔루션 탐색기에서 프로젝트 선택 -> 마우스 우클릭 후 '속성' -> 구성 속성 -> C/C++ -> 코드생성 -> 런타임 라이브러리 의 값을 하나의 값으로 모두 통일함( 다중스레드 디버그(/MTd) 나 다중쓰레드 디버그DLL(/MDd) ) 



Error Pattern



오류 404 error LNK2005: "public: bool __cdecl std::ios_base::fail(void)const " (?fail@ios_base@std@@QEBA_NXZ)이(가) msvcprtd.lib(MSVCP80D.dll)에 이미 정의되어 있습니다.


오류 405 error LNK2005: "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl std::endl(class std::basic_ostream<char,struct std::char_traits<char> > &)" (?endl@std@@YAAEAV?$basic_ostream@DU?$char_traits@D@std@@@1@AEAV21@@Z)이(가) msvcprtd.lib(MSVCP80D.dll)에 이미 정의되어 있습니다.


오류 406 error LNK2005: "public: void __cdecl std::basic_ifstream<char,struct std::char_traits<char> >::`vbase destructor'(void)" (??_D?$basic_ifstream@DU?$char_traits@D@std@@@std@@QEAAXXZ)이(가) msvcprtd.lib(MSVCP80D.dll)에 이미 정의되어 있습니다.


오류 407 error LNK2005: "public: __cdecl std::ios_base::operator void *(void)const " (??Bios_base@std@@QEBAPEAXXZ)이(가) msvcprtd.lib(MSVCP80D.dll)에 이미 정의되어 있습니다.

오류 408 error LNK2005: "public: void __cdecl std::basic_ofstream<char,struct std::char_traits<char> >::`vbase destructor'(void)" (??_D?$basic_ofstream@DU?$char_traits@D@std@@@std@@QEAAXXZ)이(가) msvcprtd.lib(MSVCP80D.dll)에 이미 정의되어 있습니다.

class 를 작성할때 내부에서 자주 쓰는 긴 이름을 가진 자료형은 typedef로 alias 를 걸게 되는데
template class일 경우 typedef 내부에도 템플릿 인자를 써야하는 상황이 온다.
그러나 typedef 내부 인자로는 아래와 같은 template 을 허용하지 않으니...



아래와 같은 우회적인(템플릿 라이브러리들 간에 거의 표준으로 사용하는 코드라고 한다.) 사용된다.


Declaration & Initialization

return-type (*function-pointer-name)(param1-type, param2-type, ...) = XXX

(ex1) General :  int (*fp)(double, double) = 0x00;
(ex2) Class Member function :  int (TmpClass::* fp2)(double, double) = 0x00;
(ex3) Class const Member function :  int (TmpClass::* fp3)(double, double) const = 0x00;


  • public inheritance : Maintains original type of super class.
  • protected and private inheritance : Changes all types of super class to its inheritance type.

public type
in super class
protected type
in super class
private type
 in super class
 public inheritance public type  protected type private type
 protected inheritance  protected type  protected type   protected type 
 private inheritance private type  private type  private type  


반올림 함수는 c에서 기본적으로 지원하지 않는다. 자주 사용되는 관계로 아래와 같이 정리해보았다.
$ gdb -c [core file name]

boost::shared_ptr
  • swap() : Leak 원인 찾느라 시간좀 걸린 녀석. 트리나 리스트 같이 객체 내에 자신의 포인터를 가지고 있는 자료형을 이용중이었는데, 특정함수서 tmp 변수로 작업후 원 object 와 swap 하는 과정에서 내부 list 에 있는 shared_ptr 이 제대로 삭제가 안되었거나 cyclic issue가 발생한 것 같다. 대입연산자 = 로 바로 해결했음.

error: ISO C++ forbids declaration of ‘자료형’ with no type
-------------------------------------------------------------------------------------------
원인 : 자료형이 제대로 선언되지 않은채 사용되었다.
해결 :
          1. 이 자료형이 선언된 헤더파일의 경로 및 파일이름이 올바른지 확인한다.
          2. namespace안에 구현된 경우일 수도 있으니 namespace를 사용했는지 확인한다.



error: 'NullLock' was not declared in this scope
-------------------------------------------------------------------------------------------
원인 : 자료형이 제대로 선언되지 않았다.
해결 :
          1. 만약 include한 파일이 include path 중에 2군대 이상 존재한다면, 첫번째 path 안에
             있는
파일이 include 된다. 해결하려면 컴파일 옵션에서 include path의 순서를 바꾸
             거나,
using namespaceObject::Something 처럼 사용하고자 하는것만 골라서 쓰면
             된다. 되도록이면 using namespace namespaceObject 처럼 모든 것을 포함시키지 말고,
             using namespaceObject::something 처럼 사용하는것 하나하나씩만 끌어다 쓰도록
             하자.


    (예) lock.h 라는 파일이 /test/lock.h 에 있고 /test/include/lock.h에 있다고 가정하자.
         컴파일 옵션은
         gcc -I/test/lock.h -I/test/include/lock.h -c -o something.o something.cpp
         일때
lock.h 는 처음 include 경로로 잡았던 /test/lock 의 lock.h를 읽어오게 된다.

          2. name space 를 사용했는지 확인한다.

error: undefined reference to 'xxx'
-------------------------------------------------------------------------------------------
원인 : 링킹 과정중 라이브러리 파일이 잘 연결되지 못했다.
해결 :
               1. 라이브러리 명과 라이브러리 경로를 확인한다.
               2. 그래도 안되면 라이브러리 순서를 바꿔본다. (다른 라이브러리에 의존적이지 않은 것을
                    뒤에 오게한다. 반드시 뒤에 기술된 라이브러리는 앞에 기술된 라이브러리를 참조하면
                   안된다)
               3. 1,2번이 안되는 예가 있다. 라이브러리끼리 서로 참조하는 경우에는 순서를 바꿔본들
                   에러는 변함없이 난다. 그런경우 다음과 같이 한다. Xlinker 는 linker 에게 옵션을 넘긴다
                   는 뜻이고 start ~ end-group 은 링크를 하나로 그루핑 하는 function 이다.
                  (예) lib1.a 와 lib2.a 가 서로 참조하는 경우 아래와 같은 옵션을 통해서 해결할 수 있다.
                         gcc -o exefile -Xlinker --start-group lib1.a lib2.a -Xlinker --end-group


error: passing 'const XXXXX' as 'this' argument of 'xxxxxx' discard qualifiers
-------------------------------------------------------------------------------------------
원인 : const로 선언한  class 에서 const 를 보장할 수 없는 함수가 호출되었다. 즉, 어떤 클래스를 
const 로 사용하기로 했는데 그 클래스의 맴버함수중에 const 속성을 보장할수 없는 것을 호출한 
경우이다.

(예) int attachFirstStringAfterSecondString( const string& First, const string& Second )
     {
              Second.attach( First );    // This line Occurs error
     }

해결 : 우선 호출한 함수에 대해 생각해봐야 한다. 이것이 const속성을 보장해야 하는 함수인지 아닌지를 말이다. 만약 이것이 상수성을 보장해야 한다면 첫번째 방법을 써야 하고, 그렇지 않은경우 클래스를 이용할때 const로 이용하지 말아야 한다. 이것은 class design 시 신중하지 않으면 나중에 골치아픈 문제를 야기시킬수 있으므로 design step에서 신경쓰도록 하자.

          1. 함수에 대해서 const 를 보장하게 만든다. (예) int displayValue(void) const;
            - 안에서 멤버변수를 변경하는 부분을 없앤다.
            - 만약 부득이하게 멤버 변수를 변경해야 하는경우 그 맴버 변수를 mutable로 선언한다.
               (예) mutable int length_;
 
           2. class 를 const 형태로 이용하지 않는다. 하지만 이 방법은 추천하지 않는다. 만약 변경될
               필요가 없는 인자 클래스를 const를 벗긴채로 사용할경우, 변경하더라도 아무런 에러를 발생
               시키지 않기 때문에 좋은 코딩스타일이라고 볼 수 없다. 신중히 생각하고 const 를 벗기도록
               하자.
 
error: expected unqualified-id ...
-------------------------------------------------------------------------------------------
원인 : 어딘가에 동일한 이름의 MACRO 가 쓰이고 있다.
해결 : 빌드하는 모든 소스를 검사하여 MACRO 이름을 바꾸거나 겹치지 않게 조치를 취한다.



binary 로 파일을 읽어오는 프로그램을 작성하다 나중에 필요할까 싶어 정리해본다.

ftell 과 fseek 만을 이용해서 file size를 얻어오는 방법을 이용하였다.

int ftell ( FILE* stream )
   - 스트림의 현재 file pointer 를 조사해서 시작점과의 거리를 바이트 단위로 리턴한다.




C++ Style : ifstream 을 통한 length 구하고 그 값을 저장하는 코드
gdb 에서 프로그램보다 먼저 signal을 잡기 때문에 간혹 디버깅하기 힘들때가 있다.
아래 명령어는 gdb shell 에 들어가서 사용하는 것이다. 시그날에는 SIGSEGV SIG32 등등 형식에 맞게 써준다.

gdb> handle 시그날 nostop
gdb> handle 시그날 noprint


참고로 argument 가 필요한 실행파일을 gdb 선언시 사용하고자 할때 --args 를 이용하면 된다.
만일 실행을 ./a.out 3 2 test.txt 로 해야한다면, 아래와 같이 선언후 gdb 모드에서 run을 해주면 된다.
$ gdb --args ./a.out 3 2 test.txt



기존 std library가 계속 누적되서 개발되다보니, 그에 따른 중
아래의 표를 보고 참고해서 각각 맞는 녀석들을 골라써야 한다.
이것 이외에도 template 관련 사항이나 함수의 인자관련 에러가 추가되었는데
위의 원문을 참고 바란다.

If missingThen include this header
find, for_each, sort <algorithm>
ostream_iterator, istream_iterator <iterator>
auto_ptr <memory>
typeid <typeinfo>
isalnum, toupper <cctype>
INT_MIN, INT_MAX, RAND_MAX <climits>
printf <cstdio>
atoi, free, rand, exit <cstdlib>
EXIT_FAILURE <cstdlib>
strcmp, strdup, strcpy, memcpy <cstring>

If missingThen include this header
<algobase.h> <algorithm>
<algo.h> <algorithm>
<alloc.h> <memory>
<bvector.h> <vector>
<complex.h> <complex>
<defalloc.h> <memory>
<deque.h> <deque>
<fstream.h> <fstream>
<function.h> <functional>
<hash_map.h> <tr1/unordered_map>
<hashtable.h> <tr1/unordered_map> or <tr1/unordered_set>
<heap.h> <queue>
<iomanip.h> <iomanip>
<iostream.h> <iostream>
<istream.h> <istream>
<iterator.h> <iterator>
<list.h> <list>
<map.h> <map>
<multimap.h> <map>
<multiset.h> <set>
<new.h> <new>
<ostream.h> <ostream>
<pair.h> <utility>
<queue.h> <queue>
<rope.h> <ext/rope>
<set.h> <set>
<slist.h> <ext/slist>
<stack.h> <stack>
<streambuf.h> <streambuf>
<stream.h> <iostream>
<tempbuf.h> <ext/memory>
<tree.h> <ext/rb_tree> or <ext/pb_ds/assoc_container.hpp>
<vector.h> <vector>




  1. Favicon of http://finsternis.tistory.com BlogIcon leanu 2009.10.08 19:19 신고

    You should add #include <numeric> if you use "std::accumulator"

상황 : 할당하고자 하는 메모리영역은 현재 잡힌 것보다 크다.

resize(n) : 메모리를 할당. 오브젝트 하나를 생성한 후, 크기가 일치할때까지 오브젝트를 계속 삽입힌다.

reserve(n) : 메모리를 할당. 끝

size() : 컨테이너 내부의 실제 오브젝트 갯수

capacity() : 할당된 메모리 총 영역 ( 컨테이너에 들어갈 수 있는 오브젝트의 총 갯수 )

아래의 소스를 보자.

결과

Resize Test ----------------
0th class is created 0x7fff63076400
1th class is copied from 0x7fff63076400 to << 0x17a0a90
2th class is copied from 0x7fff63076400 to << 0x17a0a94
3th class is copied from 0x7fff63076400 to << 0x17a0a98
Destructor : 0x7fff63076400
4th class is created 0x7fff630763f0
5th class is copied from 0x17a0a90 to << 0x17a0ab0
6th class is copied from 0x17a0a94 to << 0x17a0ab4
7th class is copied from 0x17a0a98 to << 0x17a0ab8
8th class is copied from 0x7fff630763f0 to << 0x17a0abc
Destructor : 0x17a0a90
Destructor : 0x17a0a94
Destructor : 0x17a0a98
Size : 4 Capacity : 6

Reserve Test ----------------
9th class is copied from 0x7fff630763f0 to << 0x17a0a90
Size : 1 Capacity : 3 
Destructor : 0x7fff630763f0
Destructor : 0x17a0a90
Destructor : 0x17a0ab0
Destructor : 0x17a0ab4
Destructor : 0x17a0ab8
Destructor : 0x17a0abc



Resize를 한경우 copy constructor 가 (resize 크기 - 이전 크기)만큼 일어나며, 그에 따라 size도 커짐을 알 수 있다.

Reserve를 한경우 capacity에만 영향을 미치고 size() 에는 영향을 주지 않음을 알 수 있다.

클래스 A 와 B가 있는데 A 는 B를 상속한다.
만약 클래스 A에 operator== 를 구현하고자 한다면 상속된 B의 멤버 변수에 대한 비교도 포함을 시켜야 한다.
한가지 방법으로는 클래스 A안에서 B의 멤버변수들을 모두 비교해볼수도 있지만, 이는 좀 껄쩍지근하다.
게다가 B의 멤버변수가 많아지면, 타이프하기 구찮아지고 빼먹을 확률도 높다.

두번째 방법으로는 ParentClass::operator== 를 직접 호출하는게 있다. 우연히 발견한건데 이미 많은 사람들이 알고 있을지도 ... ㅋㅋ

아래의 코드를 보면 알수 있다.



pair 자료형으로 선언한경우 operator == 를 사용하려면 이에 대해 오버로딩을 해줘야 할것 같지만
 
pair 안에서 자체적으로 first 인자와 second 인자에 대해 각각 == 을 적용시킨후 결과를 반환한다.

아래의 소스를 보면 그 의미가 좀 더 구체적으로 다가온다.
Compilation  이 나는 이유는 TEST class 에 == 를 호출하려고 하는데 정의가 되어 있지 않기 때문이다.



특정 template 클래스에 overriding 하기 위한 참조 코드.

지금까지 인터넷 검색 및 지인에게 물어본 결과,
template class 라도 operator>> 를 overriding 하는 경우 구체적인 형이 필요하다는 것이다.
(차후 개선된 답을 얻게 되면 업데이트 하겠지만, 지금 단계에서는 여기까지가 내가 내린 결론이다.)

operator >> 를 template class 내부에서 friend 로 선언할 때에는 template 로 선언할 수는 있지만, 컴파일시 뭔가 꺼림찍한 Warning을 뱉어낸다. 어차피 죄다 선언할 것이라면 friend 선언부에도 구체적인 명시를 해서 어떤 녀석들이 쓰이는지 보이는것도 괜찮을듯 싶다.

아래의 소스는 키보드로 입력받은 스트림에서 지정된 형식의 string 을 받아( , 로 구분된 두개의 단어들) 멤버변수 2개에 할당하고 그 결과를 화면에 뿌려보는 것이다.

   예) 키보드로 "abc,123" 이라고 입력하면 name_ 에는 abc가 title_에는 123 이 저장된다.



Information

C 에서 사용하는 매크로를 이용하면 된다.

1. 파일    : __FILE__
2. 줄번호 : __LINE__
3. 함수명 : __FUNCTION__ , __func__ 
                (__func__ 는 C99 에서 새로 추가된 녀석. 가능하면 _func__를 사용하자)

Example



Result

FileName : main.cpp
Line no : 5
Function : main
Function : main


Comment

이러한 매크로 들을  predefined macro (미리 선언된 매크로) 라고 하는데, 되도록이면 특정 컴파일러에 편중된 매크로보다는 표준 매크로를 사용하는 것이 멀티 플랫폼 개발에 유용하리라 본다.

표준 매크로에 대한 기술은 다음 사이트에서 찾아볼 수 있다.




앞부분의 _WINSOCKAPI_ 관련 define 부분은 winsock v1 과 winsock v2 의 충돌을 방지하기위해 넣은 코드다.

아래는 시간측정을 위해 사용한 운영체제별 구조체에 대한 설명이다. 특히나 범위나 시작하는 값이 어디서부터인지 잘 봐두는게 좋다.

struct timeval {
     long     tv_sec;    // seconds from 1970-01-01 00:00:00
     long     tv_usec;  // micro seconds
};

struct tm {
    int tm_sec;    // seconds                   [0, 59]
    int tm_min;    // minutes                    [0, 59]
    int tm_hour;   // hours                       [0, 23]
    int tm_mday; // day of the month        [1, 31]
    int tm_mon;   // months                     [0, 11]
    int tm_year;   // year since 1900
    int tm_wday; // days since sunday     [0, 6]
    int tm_yday;  // days since January 1 [0, 365]
    int tm_isdst;  // daylight savings time flag
};

typedef struct _SYSTEMTIME {
    WORD wYear;
    WORD wMonth;
    WORD wDayOfWeek;
    WORD wDay;
    WORD wHour;
    WORD wMinute;
    WORD wSecond;
    WORD wMilliseconds;
} SYSTEMTIME;



Additional Comment

컴파일된 시점의 날짜와 시간을 기록하고 싶으면 표준 매크로를 사용하면 된다.
__DATE__ 와 __TIME__ 을 이용하면 된다.


출력 결과

Date : Apr 16 2009
Time : 10:25:58
우선 소스를 보자.



위의 클래스처럼 템플릿을 사용한 클래스를 생성할때, 클래스 안에 enum 이라던지 typedef 로 재정의한 클래스 내부 타입을 정의하곤 한다. (위의 소스중 enum Direction 같이 말이다.) 그런경우 대부분 위와 같이 코딩하고 컴파일을 돌려보면 이런 메시지에 직면하게 되는데, 처음에 난 도대체 왜 에러가 나는지 몰랐다.

- Error Message
    error: expected constructor, destructor, or type conversion before 'Movement'

결론은 template에 따라 달라질 수도 있는데 

Direction 이 변수타입명인지 아닌지 몰라서 컴파일러가 해석을 못하는 것이었다. 

이는 다음과 같이 Movement::Direction에 typename을 추가하여 해결할 수 있다.


참고로 template 의 default 값을 이용하고 싶으면 그냥 클래스명만 쓰는게 아니고

<> 를 붙여야 한다.

뭐... 간단한거지만...

#ifdef AAA
       std::cout << "AAA" << std::endl;
#ifdef BBB
       std::cout << "BBB" << std::endl;
#endif // BBB
#endif // AAA

에서

만약 AAA 만 define 되면   AAA 만 출력 되고,
만약 AAA 와 BBB가 define 되면  AAA 와 BBB가 출력되지만,

만약 BBB 만 define 되면 아무것도 출력 안된다. ㅋ 

나만 몰랐나? ㅋ

$ valgrind --leak-check=full 실행파일

full 로 체크하면 메모리 릭이 쫌 나온다. 아.. 기존에 만든거 은근히 새네. 

어느정도 완성해 놓으면 하나하나 체크해 보아야 겠다 ㅋ
  1. Favicon of http://aashley.tistory.com BlogIcon st.Ashley 2008.11.24 17:45 신고

    우와 블로그 카테고리가 굉장히 많네요 ..+ㅁ+ 관심 있는 분야가 굉장히 다양하신가봐요 ㅎ
    IT 쪽이 살짝 강한 것도 같은데 ^^; 저는 블로그에 달아 나, 내가 좋아하는 것을 표현하고 네트워킹을 돕는 Seal을 만드는 sealtale.com 의 기획자입니다 ㅎ
    온라인 촛불을 아신다면 혹시 저희를 아실지 모르겠어요 ^-^;
    혹시 관심이 있으시면 살짝 보아주십사 하고 글 남기고 갑니다.
    IT 분야 뿐 아니라 다양한 seal들이 있는데 혹시 예뻐해주실 아이가 있을지 한번 보아주세요 ;ㅁ;

1. 멤버 함수파라미터default value 를 이용하고자 한다면 형선언 부분에만 넣어주고 구현 부분에는 넣지 않는다.

(예)
class testClass
{
private:
        void print(const char* message, ostream& outputStream = cerr) const;
};

void testClass::print(const char* message, ostream& outputStream) const
{
        outputStream << message;
}


2. fprintf처럼 화면에 출력할 건지 파일로 출력할 건지를 선택하여 출력하는 인자가 c++에도 있다. 바로 ostream 이란 녀석인데 이 인자로 cout 이나 cerr 를 전달하면 화면에 출력할 것이고 ofstream 으로 규정한 인자를 넘긴다면 그에 해당하는 파일로 출력될 것이다. 아래의 예제는 이 속성을 이용한 한가지 예이다. 응용해서 써보도록 하자.

(예) 위의 1번 예제에서 구현한 testCase를 참조해 보자.

int main()
{
      testClass test;
      ofstream fpout;
      fpout.open("output.txt");

      test.print("Screen output"); // use default value. It will show message into screen
      test.print("Screen output", cerr); // It will also show the message into screen
      test.print("File output", fpout);  // it will show the message into output.txt file
}

3. 생성자에 키워드 explicit 를 써준경우 =을 이용한 자동 생성자 호출을 방지하고(암시적 변환) 명시적으로 선언된 경우만 허용한다.

(예)
class test_one
{
public:
    test_one(){};
    test_one(double a){};
    ~test_one(){};
};
class test_two
{
public:
    test_two(){};
    explicit test_two(double a){};
    ~test_two(){};
};

void foo(test_one var)
{
   cout << "foo is called" << endl;
}
void foo2(test_two var)
{
   cout << "foo2 is called" << endl;
}

int main()
{
      test_one t1_1;
      test_one t1_2(300);    // 명시적 생성자.   사용가능
      test_one t1_3 = 200;   // 암시적 생성자.   사용가능
      t1_2 = 2.0;                // 암시적 생성자.   사용가능
      foo(3.0)                   // 암시적 생성자가 가능한 test_one 인자가 호출됨.
                                    // 화면에는 "foo is called"라고 출력됨
      test_two t2_1;
      test_two t2_2(300);    // 명시적 생성자.   사용가능
      test_two t2_3 = 200;   // 암시적 생성자.   사용불가. compile error발생.
      test_two t2_2 = 2.0;    // 암시적 생성자.   사용불가. compile error 발생.

}

Before Introduction of the casting
--------------------------------------------------------------------------------------------

Casting에 대한 설명 전에 당부하고 싶은 말은, 되도록 Casting 횟수를 최소화 하라는 것이다. 왜냐하면 Casting을 하다보면 틀린 코드를 쓰고도 모르는 경우가 발생할 수 있으며, Casting시 Overhead가 있기 때문이다. 꼭 필요한 것인지 다시한번 생각해볼 필요가 있는 녀석이다.

또하나 당부하고 싶은 말은, 구형스타일의 캐스트를 쓰려거든 (예) (int)32.353 C++스타일의 캐스트를 사용하라는 것이다. 코드상에서 캐스팅 영역을 발견하기도 편하고, 그로 인해 프로그래머의 의도를 좀더 쉽게 파악할 수 있기 때문이다.



Introduction & Details of the casting
--------------------------------------------------------------------------------------------

0. How to Use 

        : xxx_cast<변환타입>(변환할값)

1. static_cast

     : 일반적인 C 형태의 캐스팅이라고 생각하면된다. 변환 자료형을 써줄 필요가 없고, 특정
       자료형으로 강제로 변환하고자 할 경우에는 <> 를 이용한다.(되도록 자료형을 써주자)
       위험한 형변환시 (할당되지 않은 영역까지 침범하는 캐스팅) 에러를 발생시킨다. 하지만
       런타임시 변환에 대한 안전성보장을 하지 않으므로, dynamic_cast와 이것중 뭘 선택해야
       하는지는 프로그래머에 달려있다.

 (예1) double d = 2.3; int i = static_cast(d);
 (예2) void *b = malloc(sizeof(int) * 3); int* pi = static_cast<int>(b);

2. const_cast

      : const 형 포인터의 const 를 벗기기 위해 사용한다. 혹은 Volatileness를 제거하는 용도로도
        쓰인다.

 (예1) const int* t = new int[2]; int* e = const_cast(t);

3. reinterpret_cast

       : 전혀 관계없는 타입끼리의 캐스팅에 사용하는 강제형변환의 하나이다. Low Level에서 이용
         되며, 적용결과는 구현환경에 의존적이다(다시말해 이식성이 없다.) Low Level 제어이외에는
         사용을 금해야 하는 casting 연산자이다.

 (예1) void *b = malloc(sizeof(int) * 3); int* pi = reinterpret_cast<int>(p);

4. dynamic_cast

        : 주로 주어진 객체가 어떤 클래스 상속계통에 속한 타입인지를 결정하는 작업에 쓰인다.
          (Pointer 나 Reference)
 
          왜냐하면 캐스팅할 객체가 캐스팅 목표 객체로 변환 가능하면 그 타입의 포인터를 리턴하고
          실패하면 NULL을 리턴하기 때문이다. 상당히 신경쓰일 정도로 런타임 비용이 높은 캐스팅
          연산자이다. 캐스팅 가능여부를 판단하기위해 그 객체를 조사하게 되는데, 상속깊이가 깊거나
          다중상속이라도 쓰게 된다면 오버헤드가 크게 된다. 수행성능에 민감한 프로그램의 경우
          이 녀석의 사용에 신중을 기하자.


  1. noaster 2008.02.16 01:04 신고

    음 나는 클래스 포인터는 dynamic
    나머지는 다 static
    쓰지

  2. Favicon of http://finsternis.tistory.com BlogIcon leanu 2008.02.16 10:28 신고

    맞아~! 예전에도 프로세스 죽는거 보니까 리턴 클래스가 NULL일때 그냥 맴버함수 접근하는 경우가 많더라고. dynamic 쓰는게 좋을꺼 같네~!

1. 클래스.cpp 를 기술할때 "클래스::" 를 함수 앞에 안붙인다.

    (ex) int test() [x]     ->    int SampleClass::test()  [o]

2. Undefined reference 관련 에러

   - 해결 1 : library path 와 name 을 확인한다
   - 해결 2 : 다른 library에 영향을 받지않는 독립적인 library 부터 먼저 붙이도록 한다. 이
              문제는 static library에서 나기때문에 해당사항이 없다면 별로 고려하지 않아도
              된다. 하지만 makefile 안에 library를 추가하는경우 dependency를 고려하여 하나씩
              써 나간다면 나중에 에러를 찾는데 드는 엄청난 시간을 절약할 수 있다.



+ Recent posts