some notes on linking with shared library
==> Object.h <==
#include <stdio.h>
class Object {
public:
Object();
#ifdef TEST
void NoneVirtualFunc() {
printf("%s, size of class:%lu\n", __PRETTY_FUNCTION__, sizeof(Object));
}
#endif
#ifdef TEST
virtual void Func2();
virtual void Func1();
#else
virtual void Func1();
virtual void Func2();
#endif
virtual void Access();
#ifdef TEST
void SetOther(int other) {
m_other = other;
}
virtual void Other() {
printf("%s\n", __PRETTY_FUNCTION__);
}
#endif
private:
int m_i1;
#ifdef TEST
int m_other;
#endif
int m_i2;
};
==> Object.cpp <==
#include "Object.h"
Object::Object(): m_i1(1), m_i2(2) {
printf("%s, constructor init, i1:%d, i2:%d\n", __PRETTY_FUNCTION__, m_i1, m_i2);
}
void Object::Func1() {
printf("%s\n", __PRETTY_FUNCTION__);
}
void Object::Func2() {
printf("%s\n", __PRETTY_FUNCTION__);
}
void Object::Access() {
printf("%s, size of class:%lu, i1:%d, i2:%d\n", __PRETTY_FUNCTION__, sizeof(Object), m_i1, m_i2);
}
==> test.cpp <==
#include "Object.h"
//for more details about vtable, see: http://blog.csdn.net/haoel/article/details/1948051
int main(int argc, char* argv[]) {
Object* obj = new Object();
obj->Func1();
obj->Func2();
#ifdef TEST
obj->SetOther(1000);
#endif
obj->Access();
#ifdef TEST
obj->NoneVirtualFunc();
obj->Other(); //segmentation fault
#endif
return 0;
}
==> Makefile <==
all:
@g++ -g -fPIC -o Object.o -fno-rtti -c Object.cpp
@g++ -shared -o libObject.so Object.o
@g++ -g -Wall test.cpp -o test -L. -lObject -Wl,-rpath=.
@./test
@rm -f test *.o *.so core*
test:
@g++ -g -fPIC -o Object.o -fno-rtti -c Object.cpp
@g++ -shared -o libObject.so Object.o
@g++ -g -Wall test.cpp -o test -L. -lObject -Wl,-rpath=. -DTEST
@./test
@rm -f test *.o *.so core*
==> RESULT <==
$ make
Object::Object(), constructor init, i1:1, i2:2
virtual void Object::Func1()
virtual void Object::Func2()
virtual void Object::Access(), size of class:16, i1:1, i2:2
$ make test
Object::Object(), constructor init, i1:1, i2:2
virtual void Object::Func2()
virtual void Object::Func1()
virtual void Object::Access(), size of class:16, i1:1, i2:1000
void Object::NoneVirtualFunc(), size of class:24
make: *** [test] Segmentation fault (core dumped)
make: *** Deleting file `test'
==> KNOWLEDGE <==
一個類一旦已經編譯成so了,那么虛函數以及成員變量就都確定了,也就是影響一個類的內存映像的東西都是確定的了。
所以,修改頭文件時需要遵循以下原則:
1。可以隨意添加非虛函數;
2。不要修改虛函數的相對位置,更不要添加新的虛函數;
3。最好不要添加新的成員變量,如果添加也要在所有成員變量的后面添加,不過如果你不清楚so里的用法的話,很有可能出問題;
其實,說到本質上,就是要心里很清楚,修改前和修改后,該類的內存映像到底是怎樣的,固化在so里的代碼是不會再變化了;
有興趣的,可以debug看下虛函數表里指針的情況;如果不用-fno-rtti參數,那么vtable里會多出兩項用于typeinfo相關的內容;
增加了新的虛函數后,通過nm -C test | grep Object可以看到,生成的可執行程序里是不會有Other這個虛函數的:
00000000004008f8 W Object::NoneVirtualFunc()
0000000000400920 W Object::SetOther(int)
U Object::Object()
0000000000400a60 r Object::NoneVirtualFunc()::__PRETTY_FUNCTION__
而且新加的函數都是W類型,下面通過另一個例子來驗證W類型:
==> Object.h <==
#include <stdio.h>
class Object {
public:
void func() {
printf("It's the implementation of %s in header file\n", __PRETTY_FUNCTION__);
}
};
==> test.cpp <==
#include <stdio.h>
#include "Object.h"
int main(int argc, char* argv[]) {
Object obj;
obj.func();
return 0;
}
==> RESULT <==
$ g++ -o test test.cpp
$ ./test
It's the implementation of void Object::func() in header file
==> Object.cpp <==
#include <stdio.h>
class Object {
public:
void func();
};
void Object::func() {
printf("%s\n", __PRETTY_FUNCTION__);
}
==> RESULT <==
$ g++ -c -o Object.o Object.cpp
$ g++ -o test test.cpp Object.o
$ ./test
void Object::func()
#include <stdio.h>
class Object {
public:
Object();
#ifdef TEST
void NoneVirtualFunc() {
printf("%s, size of class:%lu\n", __PRETTY_FUNCTION__, sizeof(Object));
}
#endif
#ifdef TEST
virtual void Func2();
virtual void Func1();
#else
virtual void Func1();
virtual void Func2();
#endif
virtual void Access();
#ifdef TEST
void SetOther(int other) {
m_other = other;
}
virtual void Other() {
printf("%s\n", __PRETTY_FUNCTION__);
}
#endif
private:
int m_i1;
#ifdef TEST
int m_other;
#endif
int m_i2;
};
==> Object.cpp <==
#include "Object.h"
Object::Object(): m_i1(1), m_i2(2) {
printf("%s, constructor init, i1:%d, i2:%d\n", __PRETTY_FUNCTION__, m_i1, m_i2);
}
void Object::Func1() {
printf("%s\n", __PRETTY_FUNCTION__);
}
void Object::Func2() {
printf("%s\n", __PRETTY_FUNCTION__);
}
void Object::Access() {
printf("%s, size of class:%lu, i1:%d, i2:%d\n", __PRETTY_FUNCTION__, sizeof(Object), m_i1, m_i2);
}
==> test.cpp <==
#include "Object.h"
//for more details about vtable, see: http://blog.csdn.net/haoel/article/details/1948051
int main(int argc, char* argv[]) {
Object* obj = new Object();
obj->Func1();
obj->Func2();
#ifdef TEST
obj->SetOther(1000);
#endif
obj->Access();
#ifdef TEST
obj->NoneVirtualFunc();
obj->Other(); //segmentation fault
#endif
return 0;
}
==> Makefile <==
all:
@g++ -g -fPIC -o Object.o -fno-rtti -c Object.cpp
@g++ -shared -o libObject.so Object.o
@g++ -g -Wall test.cpp -o test -L. -lObject -Wl,-rpath=.
@./test
@rm -f test *.o *.so core*
test:
@g++ -g -fPIC -o Object.o -fno-rtti -c Object.cpp
@g++ -shared -o libObject.so Object.o
@g++ -g -Wall test.cpp -o test -L. -lObject -Wl,-rpath=. -DTEST
@./test
@rm -f test *.o *.so core*
==> RESULT <==
$ make
Object::Object(), constructor init, i1:1, i2:2
virtual void Object::Func1()
virtual void Object::Func2()
virtual void Object::Access(), size of class:16, i1:1, i2:2
$ make test
Object::Object(), constructor init, i1:1, i2:2
virtual void Object::Func2()
virtual void Object::Func1()
virtual void Object::Access(), size of class:16, i1:1, i2:1000
void Object::NoneVirtualFunc(), size of class:24
make: *** [test] Segmentation fault (core dumped)
make: *** Deleting file `test'
==> KNOWLEDGE <==
一個類一旦已經編譯成so了,那么虛函數以及成員變量就都確定了,也就是影響一個類的內存映像的東西都是確定的了。
所以,修改頭文件時需要遵循以下原則:
1。可以隨意添加非虛函數;
2。不要修改虛函數的相對位置,更不要添加新的虛函數;
3。最好不要添加新的成員變量,如果添加也要在所有成員變量的后面添加,不過如果你不清楚so里的用法的話,很有可能出問題;
其實,說到本質上,就是要心里很清楚,修改前和修改后,該類的內存映像到底是怎樣的,固化在so里的代碼是不會再變化了;
有興趣的,可以debug看下虛函數表里指針的情況;如果不用-fno-rtti參數,那么vtable里會多出兩項用于typeinfo相關的內容;
增加了新的虛函數后,通過nm -C test | grep Object可以看到,生成的可執行程序里是不會有Other這個虛函數的:
00000000004008f8 W Object::NoneVirtualFunc()
0000000000400920 W Object::SetOther(int)
U Object::Object()
0000000000400a60 r Object::NoneVirtualFunc()::__PRETTY_FUNCTION__
而且新加的函數都是W類型,下面通過另一個例子來驗證W類型:
==> Object.h <==
#include <stdio.h>
class Object {
public:
void func() {
printf("It's the implementation of %s in header file\n", __PRETTY_FUNCTION__);
}
};
==> test.cpp <==
#include <stdio.h>
#include "Object.h"
int main(int argc, char* argv[]) {
Object obj;
obj.func();
return 0;
}
==> RESULT <==
$ g++ -o test test.cpp
$ ./test
It's the implementation of void Object::func() in header file
==> Object.cpp <==
#include <stdio.h>
class Object {
public:
void func();
};
void Object::func() {
printf("%s\n", __PRETTY_FUNCTION__);
}
==> RESULT <==
$ g++ -c -o Object.o Object.cpp
$ g++ -o test test.cpp Object.o
$ ./test
void Object::func()
posted on 2015-03-12 20:50 so true 閱讀(274) 評論(0) 編輯 收藏 所屬分類: C&C++