현재 cocos2d-x 3.4버전(ndk r10c)를 사용중인데

ios에서는 to_string사용이 가능하나

android빌드시 error: 'to_string' was not declared in this scope 에러를 뱉습니다.

ndk r10c에서는 to_string함수가 존재하지 않는듯 합니다.


다행히 cocos2d라이브러리 안에 아래의 주석코드가 있네요.

말대로 stringstream을 사용합시다.

    // std::to_string is not supported on android, using std::stringstream instead.


string to_string(int value)
{
    stringstream strStream;
    strStream<<value;
    return strStream.str();
}


위와 같이 사용을 해주시면 됩니다.

예전에 만들었던 인앱 콜백을 통해 예를 들겠습니다.



선언

std::function<void(std::string productID, bool success)> inappRequestCallback;


std::function<return_type(arguments,..)> 형태로 변수를 선언합니다.

위의 예제에서는 인앱의 productID와 성공여부를 넘겨받습니다.



사용


void StoreLayer::BuyTest(string productID, bool success)

{

}



inappRequestCallback = bind(&TitleLayer::BuyTest, this, "", true);

inappRequestCallback();

or

inappRequestCallback = bind(& StoreLayer::BuyTest, storeLayer, placeholders::_1, placeholders::_2);

inappRequestCallback("", true);


bind함수를 통해 delegate(callback)를 등록시킵니다.

인자에 대해 두가지 방법으로 세팅할 수 있는데

하나는 미리 넘겨줄 인자를 등록시켜놓는 것이고, 나머지 하나는 등록시키지 않는 것 입니다.

미리 넘겨줄 인자를 등록시켜놓은 경우,
함수 사용시, 어떤 값을 넘겨주어도 이전에 등록시켰던 인자가 전달됩니다.

하지만 placeholders를 이용하면 미리 인자를 등록시키지 않고 함수 사용시 인자를 전달 할 수 있습니다.

grep 명령어 사용법

grep 명령어

grep의 의미

grep : 파일 전체를 뒤져 정규표현식에 대응하는 모든 행들을 출력한다.
egrep : grep의 확장판으로, 추가 정규표현식 메타문자들을 지원한다.
fgrep : fixed grep 이나 fast grep으로 불리며, 모든 문자를 문자 그래도 취급한다. 즉, 정         규표현식의 메타문자도 일반 문자로 취급한다.

3.1.2 grep의 동작 방법

grep에서 사용하는 정규표현식 메타문자

메타문자
기    능
사용 예
사용 예 설명
^
행의 시작 지시자
'^love'
love로 시작하는 모든 행과 대응
$
행의 끝 지시자
'love$'
love로 끝나는 모든 행과 대응
.
하나의 문자와 대응
'l..e'
l 다음에 두 글자가 나오고 e로 끝나는 문자열을 포함하는 행과 대응
*
선행문자와 같은 문자의 0개 혹은 임의개수와 대응
' *love'
0개 혹은 임의 개수의 공백 문자 후에 love로 끝나는 문자열을 포함한 행과 대응
[]
[] 사이의 문자 집합중 하나와 대응
'[Ll]ove'
love나 Love를 포함하는 행과 대응
[^ ]
문자집합에 속하지 않는 한 문자와 대응
'[^A-K]love'
A와 K 사이의 범위에 포함되지 않는 한 문자와 ove가 붙어있는 문자열과 대응
\<
단어의 시작 지시자
'\<love'
love로 시작하는 단어를 포함하는 행과 대응(vi,grep에서 지원)
\>
단어의 끝 지시자
'love\>'
love로 끝나는 단어를 포함하는 행과 대응 
(vi,grep에서 지원)
\(..\)
다음 사용을 위해 태그를 붙인다.
'\(lov\)ing'
지정된 부분을 태크1에 저장한다. 나중에 태그값을 참고하려면 \1을 쓴다. 맨 왼쪽부터 시작해 태그를 9개가지 쓸 수 있다. 왼쪽 예에서는 lov가 레지스터1에 저장되고 나중에 \1로 참고할 수 있다.
x\{m\}
문자 x를 m번 반복한다.
'o\{5\}'
문자 o가 5회 연속적으로 나오는 모든 행과 대응
x\{m,\}
적어도 m번 반복한다.
'o\{5,\}'
문자 o가 최소한 5회 반복되는 모든 행과 대응
x\{m,n\}
m회 이상 n회 이하 반복한다.
o\{5,10\}'
문자 o가 5회에서 10회 사이의 횟수로 연속적으로 나타나는 문자열과 대응

grep의 옵션

옵션
동작 설명
-b
검색 결과의 각 행 앞에 검색된 위치의 블록 번호를 표시한다. 검색 내용이 디스크의 어디쯤 있는지 위치를 알아내는데 유용하다.
-c
검색 결과를 출력하는 대신, 찾아낸 행의 총수를 출력한다.
-h
파일 이름을 출력하지 않는다.
-i
대소문자를 구분 하지 않는다.(대문자와 소문자를 동일하게 취급).
-l
패턴이 존재하는 파일의 이름만 출력한다.(개행문자로 구분)
-n
파일 내에서 행 번호를 함께 출력한다.
-s
에러 메시지 외에는 출력하지 않는다. 종료상태를 검사할 때 유용하게 쓸 수 있다.
-v
패턴이 존재하지 않는 행만 출력한다.
-w
패턴 표현식을 하나의 단어로 취급하여 검색한다.

# grep -n '^jack:' /etc/passwd
(/etc/passwd 파일에서 jack을 찾는다. jack이 행의 맨 앞에 있으면 행 번호를 화면으로 출력한다.)

3.1.3 grep과 종료 상태
grep은 파일 검색의 성공 여부를 종료 상태값으로 되돌려준다.
패턴을 찾으면 0, 패턴을 찾을 수 없으면 1, 팡리이 존재하지 않을 경우 2
sed,a자 등은 검색의 성공 여부에 대한 종료 상태값을 반환하지 않는다. 다만 구문 에러가 있을 경우에만 에러를 보고한다.

3.2 정규표현식을 사용하는 grep의 예제
# grep NW datafile
# grep NW d*
(d로 시작하는 모든 파일에서 NW를 포함하는 모든 행을 찾는다.)
# grep '^n' datafile
(n으로 시작하는 모든 행을 출력한다.)
# grep '4$' datafile
(4로 끝나는 모든 행을 출력한다.)
# grep TB Savage datafile
(TB만 인자이고 Savage와 datafile은 파일 이름이다.)
# grep 'TB Savage' datafile
(TB Savage를 포함하는 모든 행을 출력한다.)
# grep '5\.' datafile
(숫자 5, 마침표, 임의의 한 문자가 순서대로 나타나는 문자열이 포함된 행을 출력한다.)
# grep '\.5' datafile
(.5가 나오는 모든 행을 출력한다.)
# grep '^[we]' datafile
(w나 e로 시작하는 모든 행을 출력한다.)
# grep '[^0-9]' datafile
(숫자가 아닌 문자를 하나라도 포함하는 모든 행을 출력한다.)
# grep '[A-Z][A-Z] [A-Z]' datafile
(대문자 2개와 공백 1개, 그리고 대문자 하나가 연이어 나오는 문자열이 포함된 행을 출력한다.)
# grep 'ss* ' datafile
(s가 한 번 나오고, 다시 s가 0번 또는 여러번 나온 후에 공백이 연이어 등장하는 문자열을 포함한 모든 행을 출력한다.)
# grep '[a-z]\{9\}' datafile
(소문자가 9번 이상 반복되는 문자열을 포함하는 모든 행을 출력한다.)
# grep '\(3\)\.[0-9].*\1 *\1' datafile
(숫자 3,마침표,임의의 한 숫자,임의 개수의 문자,숫자 3(태그),임의 개수의 탭 문자,숫자 3의 순서를 갖는 문자열이 포한된 모든 행을 출력한다.)
# grep '\<north' datafile
(north로 시작하는 단어가 포함된 모든 행을 출력한다.)
# grep '\<north\>' datafile
(north라는 단어가 포함된 모든 행을 출력한다.)
# grep '\<[a-z].*n\>' datafile
(소문자 하나로 시작하고, 이어서 임의 개수의 여러 문자가 나오며, n으로 끝나는 단어가 포함된 모든 행을 출력한다. 여기서 .*는 공백을 포함한 임의의 문자들을 의미한다.)

3.3 grep에 옵션 사용
# grep -n '^south' datafile
(행번호를 함께 출력한다.)
# grep -i 'pat' datafile
(대소문자를 구별하지 않게 한다.)
# grep -v 'Suan Chin' datafile
(문자열 Suan Chin이 포함되지 않은 모든 행을 출력하게 한다. 이 옵션은 입력 파일에서 특정 내용의 입력을 삭제하는데 쓰인다.
# grep -v 'Suan Chin' datafile > black
# mv black datafile
)
# grep -l 'SE' *
(패턴이 찾아진 파일의 행 번호 대신 단지 파일이름만 출력한다.)
# grep -w 'north' datafile
(패턴이 다른 단어의 일부가 아닌 하나의 단어가 되는 경우만 찾는다. northwest나 northeast 등의 단어가 아니라, north라는 단어가 포함된 행만 출력한다.)
# grep -i "$LOGNAME" datafile
(환 경변수인 LOGNAME의 값을 가진 모든 행을 출력한다. 변수가 큰따옴표로 둘러싸여 있는 경우, 쉘은 변수의 값으로 치환한다. 작은따옴표로 둘러싸여 있으면 변수 치환이 일어나지 않고 그냥 $LOGNAME 이라는 문자로 출력된다.)

3.4 egrep
egrep(extended grep) : grep에서 제공하지 않는 확장된 정규표현식 메타문자를 지원  한다.
                                     grep와 동일한 명령행 옵션을 지원한다.
egrep에서 지원하는 확장 메타문자

메타문자
기능
사용 예
사용 예 설명
+
선행문자와 같은 문자의 1개 혹은 임의 개수와 대응
'[a-z]+ove'
1개 이상의 소문자 뒤에 ove가 붙어있는 문자열과 대응. move,approve,love,behoove 등이 해당된다.
?
선행문자와 같은 문자의0개 혹은 1개와 대응
'lo?ve'
l 다음에 0개의 문자 혹은 하나의 문자가 o가 나오는 문자열과 대응. love,lve 등이 해당된다.
a|b
a 혹은 b와 대응
'love|hate'
love 혹은 hate와 대응.
()
정규표현식을 묶어준다
'love(able|ly)'
lovable 혹은 lovely와 대응.
'(ov)+'
ov가 한 번 이상 등장하는 문자열과 일치.

3.4.1 egrep 예제
# egrep 'NW|EA' datafile
(NW나 EA가 포함된 행을 출력한다.)
# egrep '3+' datafile
(숫자 3이 한 번 이상 등장하는 행을 출력한다.)
# egrep '2\.?[0-9]' datafile
(숫자 2 다음에 마침표가 없거나 한 번 나오고, 다시 숫자가 오는 행을 출력한다.)
# egrep ' (no)+' datafile
(패턴 no가 한 번 이상 연속해서 나오는 행을 출력한다.)
# egrep 'S(h|u)' datafile
(문자 S 다음에 h나 u가 나오는 행을 출력한다.)
# egrep 'Sh|u' datafile
(패턴 Sh나 u를 포함한 행을 출력한다.)

3.5 고정 grep 과 빠른 grep
fgrep : grep 명령어와 동일하게 동작한다. 다만 정규표현식 메타문자들을 특별하게 취급하지
          않는다.
# fgrep '[A-Z]****[0-9]..$5.00' file
([A-Z]****[0-9]..$5.00 이 포함된 행을 출력한다. 모든 문자들을 문자 자체로만 취급한다.)


==============================================================================================
grep 명령어

◈ 기본문법

grep [-civnlw] pattern file_name1 [file_name2]

-c    패턴이 일치하는 행의 수를 출력
-i     배교시 대소문자를 구별하지 않음
-v    지정한 패턴과 일치하지 않는 행만 출력
-n    행의 번호를 함께 출력
-l     패턴이 포함된 파일의 이름을 출력
-w   패턴이 전체 단어와 일치하는 행만 출력

◈ 정규표현식 사용 예

^freeman       freeman으로 시작하는 행
freeman$       freeman으로 끝나는 행
freema*         freema로 시작하는 단어
f.....n            f로 시작하고 n으로 끝나는 7자리 단어
[a-d]           a,b,c,d로 시작하는 단어
[fF]reeman   freeman또는 Freeman으로 시작하는 단어

◈ 사용 예

$ grep Sunny grep.data         --> Sunny가 들어 있는 행을 출력
$ grep -n Sunny grep.data     --> Sunny가 들어 있는 행을 번호와 함께 출력
$ grep '^S' grep.data             --> 첫문자가 S로 시작하는 행을 출력
$ grep 'Thank you' grep.data  --> 문자열 Thank you가 들어 있는 행을 출력

--------------------------------------------------------------------------------------------------------


find 명령어

◈ 기본문법
find path [expression] [action]

-name file_name          검색 대상 파일명을 입력. 파일명으로 [], ? * 의 메타문자를 사용할 수 있음.
-type [file_type]          검색 대상 파일의 종류를 지정.  b(Block), c(Character), d(Directory), p(Named Pipe)
                                                                      f(Regular File), l(Symbolic Link), s(Socket)
-user uname               uname은 검색 파일의 소유주 또는 UID.
-group gname             gname은 검색 파일의 소유그룹 또는 GID.
-size [+-]num[bck]     검색 파일의 크기를 지정.  num(일치), +num(이상), -num(이하)
                                                               b(Block,512Byte), c(Byte), k(KByte)
-perm mode                주어진 접근 권한을 갖는 파일을 검색. (8진수로 기술)
-atime [+-]n               파일이 읽힌 최근 시간
-ctime [+-]n               파일의 소유주나 권한이 바뀐 최근 시간
-mtime [+-]n               파일이 수정된 최근 시간
-prune                       서브 디렉토리로 내려가지 않고 현재 디렉토리에서만 검색
-print                         검색 후에 행할 작업 옵션 : 검색결과 출력
-exec command {}\;   검색 후에 행할 작업 옵션 : 결과에 특정 명령을 실행하도록 명령


◈ 사용 예
$ find .  --> -print옵션은 일반적으로 디폴트이다. 따라서 'find . '은 'find . -print'와 같다.

$ find . -name "*.c" -print
$ find . -name "ip*.c" -print --> ip로 시작하며 확장자가 .c로 끝나는 파일 검색

$ find . -type d -print        --> 현재 디렉토리 하위(서브 포함)에서 디렉토리를 찾아 표시
$ find . -name lib -type d  --> 현재 디렉토리 하위(서브 포함)에서 lib라는 이름의 디렉토리 표시

$ find . -size +56 -print                         --> 파일 크기가 56블록보드 큰 것을 검색
$ find . -size +800c -size -900c -print    --> 파일 크기가 800Byte보다 크고 900Byte보다 작은 것을 검색

$ find . -perm -1 -print   --> other에 실행권한이 있는 파일 검색. 1은 '--------X'를 의미
$ find . -perm -44 -print  --> group에 읽기권한, other에 읽기권한이 있는 파일 검색
$ find . -perm 664 -print  --> user와 group에 읽기와 쓰기 권한, other에 읽기권한이 있는 파일 검색

$ find . -mtime +3 -print  --> 수정한지 3일이 지난 파일을 검색(5일~)
$ find . -mtime 3 -print   --> 수정한지 3일이 된 파일을 검색
$ find . -mtime -3 -print  --> 수정한지 3일이 못된 파일을 검색(0,1,2일)

$ find . -name "*.o" -print
$ find . -name "*.o" -exec rm {} \; --> .o 파일을 찾아서 그 결과를 rm명령어 실행시 인수로 전달
$ find . -name "*.o" | wc -l            --> .o 파일을 찾아서 파이프로 그 결과를 wc명령의 입력으로 전달

※ fine는 논리 연산이 가능하다
  -a (And),  -o (Or),  ! (Not)

$ find . -name "*.log" -o -name "*.o" -print                        --> 확장자가 '.log'이거나 '.o'인 것을 검색
$ find . \( -name "*.log" -o -name "*.o" \) -print              --> 위와 동일. '('를 사용하려면 '\'을 붙여야 함
$ find . ! \( -name "*.log" -o -name "*.o" \) -print            --> 괄호 사용으로 이렇게 전체부정등이 가능
                                                                                   '.log'와 '.o' 이외의 파일을 검색
$ find . \( -name "*.log" -o -name "*.o" \) -exec rm {} \;  --> '.log'나 '.o'인 것을 찾아 삭제
 --------------------------------------------------------------------------------------------------------xargs 명령어 

find . | xargs 를 하면 find명령의 결과가 한 행으로 출력된다. 즉, xargs는 여러행을 한행으로 만드는 역할을 한다.

$ find . -name "*.c" -exec grep test {} \;
$ find . -name "*.c" | xargs grep test

첫번째 명령은 find을 결과가 여러행일 때, 그 행의 수만큼 grep명령어를 실행한다.
두번째 명령은 find의 결과를 xargs가 한 행으로 만들어 grep에 전달하므로 grep는 한번만 실행된다.

◈ 사용 예
$ find . \(-name "*.log" -o -name "*.o"\) | xargs rm  --> .log와 .o 파일을 찾아서 삭제
$ find . -name *.php -exec chmod 755 {} \;  --> .php파일을 찾아서 접근권한을 755로 변경. chmod 매번 실행
$ find . -name *.php | xargs chmod 755         --> 위와 같음. chmod 한번 실행
$ find . | xargs grep -l "freeman" | xargs rm    --> freeman이라는 문자열을 포함한 파일을 찾아서 지움

출처 : http://lkrox.blogspot.kr/2013/01/grep.html


rmdir을 이용하면 폴더 삭제가 가능하지만

폴더 하위에 내용물이 있을 경우 안되더군요.(-f(force) 도 안됨)


그런 경우에는 rm -rf [폴더명]을 사용하면 됩니다.

'Notes > Tech History' 카테고리의 다른 글

Windows NTSTATUS 코드 전체 표 (STATUS_ 에러 코드 정리)  (0) 2019.01.02
grep 명령어  (0) 2015.03.20
zip 명령어  (0) 2015.03.20
프로그래밍 언어 순위  (0) 2012.02.02
파일 입출력, 파일 포인터(FILE* fp)  (0) 2012.01.02

zip 명령어


zip [destination] [source]


-r  : 하위 폴더까지 전부 압축


source에 폴더 경로(ex : a/b/c)로 할 경우, 폴더 경로까지 전부 압축됩니다.

해결법을 못찾아서 cd로 우회

'Notes > Tech History' 카테고리의 다른 글

grep 명령어  (0) 2015.03.20
command line에서 폴더 삭제  (0) 2015.03.20
프로그래밍 언어 순위  (0) 2012.02.02
파일 입출력, 파일 포인터(FILE* fp)  (0) 2012.01.02
싱글턴 클래스  (0) 2011.10.17

2012년 2월자 기준

1위 - JAVA
2위 - C
3위 - C#
4위 - C++
5위 - Objective-C
6위 - PHP
7위 - Visual Basic
8위 - Python
9위 - Perl
10위 -  Java script

'Notes > Tech History' 카테고리의 다른 글

command line에서 폴더 삭제  (0) 2015.03.20
zip 명령어  (0) 2015.03.20
파일 입출력, 파일 포인터(FILE* fp)  (0) 2012.01.02
싱글턴 클래스  (0) 2011.10.17
OpenAL의 시작  (3) 2010.12.02
헤더파일 : StoreKit/StoreKit.h
라이브러리파일 : StoreKit.framework
딜리게이트 : SKProductsRequestDelegate

상품 요청
SKProductsRequest *preq = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:PRODUCT_ID]];
preq.delegate = self;
[preq start]; 
 - PRODUCT_ID : In app purchase에 등록한 상품 아이디를 입력하시면 됩니다.
ex)com.sadun.app.item1

상품 요청에 대한 응답
-(void)productsRequest(SKProductsRequest*)req didReceiveResponse:(SKProductsResponse*)response
{
    if([response.products count] >0)
    {
        for( SKProduct* product in response.products )
        {
            SKPayment *pPayment = [SKPayment paymentWithProduct:product];

            NSLog(@"Title:%@", product.localizedTitle);
            NSLog(@"Description:%@", product.localizedDescription);
            NSLog(@"Price:%@", product.price);

            [[SKPaymentQueue defaultQueue] addPayment:pPaymen];
        }
    }
    if([response.invalidProductIdentifiers count] > 0)
    {
        printf("find invalid product\n");
        for(NSString* invalidString in [response invalidProductIdentifiers])
        {
            NSLog(@"Invalid Identifiers:%@", invalidString);
        }
    }
    [req autorelease];
}

결제 후 처리
-(void)paymentQueue:(SKPaymentQueue*)queue updatedTransactions:(NSArray*)transactions
{
    for( SKPaymentTransaction* tran in transactions )
    {
        switch( tran.transactionState )
        {
            case SKPaymentTransactionStatePurchasing:
                /*----------------------------------------
                구매 중 처리
                ----------------------------------------*/
                break;
            case SKPaymentTransactionStatePurchased:
                /*----------------------------------------
                구매 후 처리
                ----------------------------------------*/
                break; 
            case SKPaymentTransactionStateRestored:
                /*----------------------------------------
                이미 구매 됨 처리
                ----------------------------------------*/
                break; 
            case SKPaymentTransactionStateFailed:
                /*----------------------------------------
                구매 실패 처리
                ----------------------------------------*/
                break;
            default:
                break;
        }
    }
}


아이폰은 잠겨져있는 것들이 많다.
사용자들에게는 상관없는것들은 다 접근이 힘들다.

resource폴더
 - resource폴더는 어플리케이션에 쓰일 리소스들이 있는 폴더다. 프로그래머는 이곳에 리소스들을 넣어놓고 접근을하여 사용한다.
 - 읽기만 가능.
 - 접근방법
NSString* resourceDir = [[NSBundle mainBundle] resourcePath];
const char* szResourceDir = [resourceDir UTF8String];

document폴더
 -  document폴더는 어플리케이션에 필요한 데이터들이 있는 폴더다. 프로그래머는 이곳에서 필요한 데이터를 저장하고 불러와 사용할 수 있다.
 - 읽고, 쓰는것 가능.
 - 접근방법
NSArray* pMyPathList = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES);
NSString* pMyPath = [pMyPathList objectAtIndex:0];
const char* szResourceDir = [pMyPath UTF8String];

그 다음엔 string함수들을 이용해서 알아서 쓰면된다.
파일포인터는 쓸때마다 까먹는것 같습니다.
사용하는 함수들도 많고... fopen할때도 옵션은 또 뭐 그리 많은지

파일포인터란
파일을 가르키는 포인터입니다.

FILE* fp = fopen("FileName.txt", "rb");
FILE* - 파일포인터 입니다. 
fopen -  파일을 불러오는 함수입니다.
"FileName.txt" -  파일 이름입니다.
"rb" - 파일을 불러올때의 옵션입니다.
 
파일 옵션
r
- 읽기 전용, 파일이 존재하지 않을 경우 NULL을 리턴.
w
- 쓰기 전용, 파일이 존재하지 않을 경우 새로 만들고, 파일이 존재할 경우 삭제하고 새로 만든다.
a
- append(덧붙이다), 파일이 존재하지 않을 경우 새로 만들고, 파일이 존재할 경우 파일 맨 끝에 파일포인터가 존재하게 된다. 맨 끝에서부터 쓰기가능.

r+ -  읽기, 쓰기 - 파일이 존재하지 않을 경우 NULL을 리턴.
w+ - 읽기, 쓰기 - 파일이 존재하지 않을 경우 새로 만들고, 파일이 존재할 경우 삭제하고 새로 만든다.
a+ - append(덧붙이다.),   파일이 존재하지 않을 경우 새로 만들고, 파일이 존재할 경우 파일의 맽 끝에 파일포인터가 존재하게 된다. 읽기는 fseek로 지정한 file pointer위치에서 가능하나 쓰기는 파일 끝부분에서만 가능.

b - 바이너리형식
t - 텍스트형식 

'Notes > Tech History' 카테고리의 다른 글

zip 명령어  (0) 2015.03.20
프로그래밍 언어 순위  (0) 2012.02.02
싱글턴 클래스  (0) 2011.10.17
OpenAL의 시작  (3) 2010.12.02
TCP기반의 에코서버/클라이언트  (0) 2010.08.19

GCC C++ Link problems on small embedded target

Thought someone might be interested in this...

I spent Thursday night and Friday night investigating some link errors I was getting on my robot project, which is small embedded ARM7 target compiling C++ code under GCC.

So here is the detail of the errors:

speed_control.o: In function `~Speed_Control':
source/speed_control.cpp:35: undefined reference to `operator delete(void*)'
speed_control.o: In function `~Sensing_Callback':
source/motor_sensing.h:38: undefined reference to `operator delete(void*)'
speed_control.o:(.rodata._ZTI13Speed_Control[typeinfo for Speed_Control]+0x0): undefined reference to `vtable for __cxxabiv1::__vmi_class_type_info'
speed_control.o:(.rodata._ZTI16Sensing_Callback[typeinfo for Sensing_Callback]+0x0): undefined reference to `vtable for __cxxabiv1::__class_type_info'
speed_control.o:(.rodata._ZTV16Sensing_Callback[vtable for Sensing_Callback]+0x8): undefined reference to `__cxa_pure_virtual'


All of these problems were caused by the fact that I'm not using the C++ libraries - either the compiler C++ support libraries or the standard libraries. And the very summarized version is that none of them were particularly hard to overcome - once you knew why they were happening! This post is about what they are.

Why aren't I using the standard stuff? This is because I don't have much flash or RAM. Well, actually I have 128K of Flash (which I expect I won't use up) and 60K of RAM (which I'm going use a significant fraction for a large data store ... all will be revealed in a later blog entry). It's quite common for embedded systems to roll their own nearly everything. I do link against certain libraries. But certainly nothing like heap management, cout or printf.

Undefined References to class_type_info

Starting with with the undefined references to
`vtable for __cxxabiv1::__vmi_class_type_info'
and
`vtable for __cxxabiv1::__class_type_info'
- these are related to RTTI (run-time type information) as suspected, and are functions patched into the RTTI table. There is a pointer to this from the vtable.

This is the vtable:

507 _ZTV16Sensing_Callback:
508 0000 00000000 .word 0
509 0004 00000000 .word _ZTI16Sensing_Callback
510 0008 00000000 .word __cxa_pure_virtual
511 000c 00000000 .word _ZN16Sensing_CallbackD1Ev
512 0010 00000000 .word _ZN16Sensing_CallbackD0Ev


As you can see, address 4 points at the type table.

492 _ZTI16Sensing_Callback:
493 0000 08000000 .word _ZTVN10__cxxabiv117__class_type_infoE+8
494 0004 00000000 .word _ZTS16Sensing_Callback


Obviously those are mangled names ... and I've left off a whole other block - this is the pure abstract base class, effectively an interface, part of a concrete class.

Since I'm not using rtti at all, we can get rid of this by adding "-fno-rtti" to the gcc command line options. Both errors go away.


Undefined Reference to `__cxa_pure_virtual'

This one is interesting. Effectively it's a function that is called if you actually (somehow) call apure virtual member function. Remember that you don't give them a definition (by putting =0) in the class after the member function definition. As you know - this does two things, forces you to define it in any derived classes and stop you making a concrete version of that base class.

I guess you've have to be hacking the vtable or doing some very bizarre casting to get this at all without the compiler spotting it. Either way, I think it's part of the language standard I think - I believe gcc's standard lib does an abort.

eCos has some information on it, as does the OS Dev Wiki.

http://sourceware.org/ml/ecos-patches/2003-03/msg00209.html

http://www.osdev.org/wiki/C_PlusPlus

We just sit in a loop, because I think it will never happen to us.

extern "C" void __cxa_pure_virtual(void)
{
// call to a pure virtual function happened ... wow, should never happen ... stop
while(1)
;
}



Undefined Reference to operator delete(void *)

The final ones quite good ... and Google really didn't help direct me to the information in any sort of quick way.

So, I don't use new and delete - because we haven't got a heap, and the memory on the single-chip microcontroller is not really large enough to use that type memory management (certainly not with my usage). It's all stack based and static objects for us. But that's ok.

So why is gcc generating a delete? Turns out there is more than one destructor in gcc (and there also can be two types of constructor as well - but I'll just cover destructors here). If the destructors are virtual they will appear in the vtable (there are two in the vtable one above - but another class has three). How gcc decides to generate 2 or 3, I haven't found out.

In summary, these three are:
  • in-charge deleting (the destructor also deletes the memory space) ... has D0Ev at the end of the mangled name.
  • in-charge (the destructor is allowed call other destructors) ... has D1Ev at the end of the mangled name.
  • not-in-charge (the destructor is NOT allowed to call other destructors ... and this has D2Ev at the end of the mangled name.
(v means void (i.e. no parameters) by the way).

So why the difference between in-charge and not-in-charge? Well, it's got to do with virtual inheritance (as opposed to virtual member functions). The summarised version is that these are multiple inherited classes that have a single base class at some point where we want one object copy rather than a copy for each derived path.

The rules say, to avoid trying to 'destruct' these common base classes multiple times, that only the most-derived class can sort out calling the destructors (and this is probably the simplest method, anyhow).

Also note that multiple destructors is not the only way of handling this ... earlier versions of gcc passed parameters into the destructor and generated code to select the desired operation. However, you get this speed overhead all the time. Extra entries removes this problem - because you can call the one you want directly.

The 'in-charge deleting' version is, I'm guessing, when you destroy an object by calling delete on it. Therefore gcc only needs to arrange to call the destructor. Of course this will always be "in-charge", since it's likely to be at the top of a hierarchy ("most-derived").

Some more information for this topic, mainly about virtual inheritance:

The OS Dev Wiki touches on the solution: http://www.osdev.org/wiki/C_PlusPlus

This GNU list describes the virtual inheritance stuff, what's called when:http://lists.gnu.org/archive/html/bug-gnu-utils/2004-07/msg00042.html

Notes about the implementation: http://gcc.gnu.org/ml/gcc-patches/2000-04/msg00403.html

Actual details of what's called when from the closed items of a bug tracking system. Search for C-5 and C-6 - there are quite a few more details. C-4 is interesting as well.http://www.codesourcery.com/cxx-abi/cxx-closed.html

My actual solution? Added this to my project...


void operator delete(void *)
{
// should never get here ... we don't use new
while(1)
;
}