如何在C中使用C++的类
来源:互联网 发布:网络红猫红小胖照片 编辑:程序博客网 时间:2024/05/22 02:00
Today I had a little chat with Michiel on #gnome-nl regarding the use of C++ classes in C code (he started learning C again ;-)).
I was fascinated (well, sort of) by this, and tried to get something working. Here's the result:
* First we need a C++ class, using one header file (Test.hh)
class Test {
public:
void testfunc();
Test(int i);
private:
int testint;
};
and one implementation file (Test.cc)
#include <iostream>
#include "Test.hh"
using namespace std;
Test::Test(int i) {
this->testint = i;
}
void Test::testfunc() {
cout << "test " << this->testint << endl;
}
This is just basic C++ code.
* Then we need some glue code. This code is something in-between C and C++. Again, we got one header file (TestWrapper.h, just .h as it doesn't contain any C++ code)
typedef void CTest;
#ifdef __cplusplus
extern "C" {
#endif
CTest * test_new(int i);
void test_testfunc(const CTest *t);
void test_delete(CTest *t);
#ifdef __cplusplus
}
#endif
and the function implementations (TestWrapper.cc, .cc as it contains C++ code):
#include "TestWrapper.h"
#include "Test.hh"
extern "C" {
CTest * test_new(int i) {
Test *t = new Test(i);
return (CTest *)t;
}
void test_testfunc(const CTest *test) {
Test *t = (Test *)test;
t->testfunc();
}
void test_delete(CTest *test) {
Test *t = (Test *)test;
delete t;
}
}
Some things you should notice:
1. typedef void CTest
We typedef CTest to void. This way we can use "CTest *" in our C code as if it's a normal C type, whilst we have compile-time type checks (sort of at least :-)), and it's cleaner than always using "void *"
2. The use of "extern "C" { }" around all functions (both definitions and implementations). We need this so the compiler won't name-mangle the resulting binaries. If you want to see what name-mangling is:
$ cat test.c
#include <iostream>
using namespace std;
void test() {
cout << "test" << endl;
}
int main(int argc, char *argv[]) {
test();
return 0;
}
$ g++ -o nmtest test.c
$ ./nmtest
test
$ nm nmtest
*blablabla*
08048818 t _Z41__static_initialization_and_destruction_0ii
080487c4 T _Z4testv
U _ZNKSs4sizeEv@@GLIBCXX_3.4
U _ZNKSsixEj@@GLIBCXX_3.4
*blablabla*
As you can see, our "test()" function has been renamed to "_Z4testv" by the compiler. This is needed to allow polyphormism in C++, but we don't want this in our C wrapper of course, as we want to know the name of the function we will call!
This implies we need another function name for every polyphormistic (SP?) class function of our C++ class in the C wrapper.
* At last, we need some code to test our work (main.c):
#include <stdio.h>
#include "TestWrapper.h"
int main() {
CTest *t = NULL;
t = test_new(5);
test_testfunc(t);
test_delete(t);
t = NULL;
return 0;
}
This is, once more, braindead simple (C) code, where we use the functions defined in TestWrapper.h.
* Last but not least, we need to compile everything. I made a basic Makefile to do this (Makefile):
CFLAGS=-Wall -Werror -g -ansi -pedantic -std=c89
CCFLAGS=-Wall -Werror -g
LDFLAGS=-g -Wall -lstdc++
OBJS=Test.o TestWrapper.o main.o
PROG=test
all: $(PROG)
default: all
%.o: %.cc
$(CC) $(CCFLAGS) -c $<
%.o: %.c
$(CC) $(CFLAGS) -c $<
$(PROG): $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) -o $@
clean:
rm -f $(OBJS)
rm -f $(PROG)
Now we can simply call "make" to build the project:
$ make
cc -Wall -Werror -g -c Test.cc
cc -Wall -Werror -g -c TestWrapper.cc
cc -Wall -Werror -g -ansi -pedantic -std=c89 -c main.c
cc Test.o TestWrapper.o main.o -g -Wall -lstdc++ -o test
Finally, we test the resulting binary:
$ ./test
test 5
which is the expected result.
Obviously, writing a wrapper like this by hand can be a boring task. It might be possible to automate/s cript this, but I don't know whether the result is worth the time one puts into it. Just use plain C, we don't need C++
from:http://blog.eikke.com/index.php/ikke/2005/11/03/using_c_classes_in_c
I was fascinated (well, sort of) by this, and tried to get something working. Here's the result:
* First we need a C++ class, using one header file (Test.hh)
class Test {
public:
void testfunc();
Test(int i);
private:
int testint;
};
and one implementation file (Test.cc)
#include <iostream>
#include "Test.hh"
using namespace std;
Test::Test(int i) {
this->testint = i;
}
void Test::testfunc() {
cout << "test " << this->testint << endl;
}
This is just basic C++ code.
* Then we need some glue code. This code is something in-between C and C++. Again, we got one header file (TestWrapper.h, just .h as it doesn't contain any C++ code)
typedef void CTest;
#ifdef __cplusplus
extern "C" {
#endif
CTest * test_new(int i);
void test_testfunc(const CTest *t);
void test_delete(CTest *t);
#ifdef __cplusplus
}
#endif
and the function implementations (TestWrapper.cc, .cc as it contains C++ code):
#include "TestWrapper.h"
#include "Test.hh"
extern "C" {
CTest * test_new(int i) {
Test *t = new Test(i);
return (CTest *)t;
}
void test_testfunc(const CTest *test) {
Test *t = (Test *)test;
t->testfunc();
}
void test_delete(CTest *test) {
Test *t = (Test *)test;
delete t;
}
}
Some things you should notice:
1. typedef void CTest
We typedef CTest to void. This way we can use "CTest *" in our C code as if it's a normal C type, whilst we have compile-time type checks (sort of at least :-)), and it's cleaner than always using "void *"
2. The use of "extern "C" { }" around all functions (both definitions and implementations). We need this so the compiler won't name-mangle the resulting binaries. If you want to see what name-mangling is:
$ cat test.c
#include <iostream>
using namespace std;
void test() {
cout << "test" << endl;
}
int main(int argc, char *argv[]) {
test();
return 0;
}
$ g++ -o nmtest test.c
$ ./nmtest
test
$ nm nmtest
*blablabla*
08048818 t _Z41__static_initialization_and_destruction_0ii
080487c4 T _Z4testv
U _ZNKSs4sizeEv@@GLIBCXX_3.4
U _ZNKSsixEj@@GLIBCXX_3.4
*blablabla*
As you can see, our "test()" function has been renamed to "_Z4testv" by the compiler. This is needed to allow polyphormism in C++, but we don't want this in our C wrapper of course, as we want to know the name of the function we will call!
This implies we need another function name for every polyphormistic (SP?) class function of our C++ class in the C wrapper.
* At last, we need some code to test our work (main.c):
#include <stdio.h>
#include "TestWrapper.h"
int main() {
CTest *t = NULL;
t = test_new(5);
test_testfunc(t);
test_delete(t);
t = NULL;
return 0;
}
This is, once more, braindead simple (C) code, where we use the functions defined in TestWrapper.h.
* Last but not least, we need to compile everything. I made a basic Makefile to do this (Makefile):
CFLAGS=-Wall -Werror -g -ansi -pedantic -std=c89
CCFLAGS=-Wall -Werror -g
LDFLAGS=-g -Wall -lstdc++
OBJS=Test.o TestWrapper.o main.o
PROG=test
all: $(PROG)
default: all
%.o: %.cc
$(CC) $(CCFLAGS) -c $<
%.o: %.c
$(CC) $(CFLAGS) -c $<
$(PROG): $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) -o $@
clean:
rm -f $(OBJS)
rm -f $(PROG)
Now we can simply call "make" to build the project:
$ make
cc -Wall -Werror -g -c Test.cc
cc -Wall -Werror -g -c TestWrapper.cc
cc -Wall -Werror -g -ansi -pedantic -std=c89 -c main.c
cc Test.o TestWrapper.o main.o -g -Wall -lstdc++ -o test
Finally, we test the resulting binary:
$ ./test
test 5
which is the expected result.
Obviously, writing a wrapper like this by hand can be a boring task. It might be possible to automate/s cript this, but I don't know whether the result is worth the time one puts into it. Just use plain C, we don't need C++
from:http://blog.eikke.com/index.php/ikke/2005/11/03/using_c_classes_in_c
- 如何在C中使用C++的类
- 如何在原有的Objective-C中使用Swift和在Swift中使用Objective-C
- 如何在C#中使用C/C++写的DLL。
- 如何在c语言中使用java传入的String
- 如何在C++Builder中使用ACE
- 如何在c:forEach中使用索引
- 如何在C Builder中使用全局变量
- 如何在C++Builder中使用全局变量
- 在C++中如何使用C
- 明白在C++中如何使用C
- 如何在c:forEach中使用索引
- 在C++中如何使用C
- 如何在C程序中使用C++类
- C/C++的一点技巧:如何在控制台工程中使用CString类
- 如何在VC6中使用Intel C/C++ 编译器
- 如何在Open C/C++应用中使用Boost.Regex
- 如何在C#Winform程序中正确使用登录窗体
- 在C++Builder中如何使用游戏操纵杆
- 达芬奇平台DM644X(ARM9, Linux-2.6.10)BSP之clock.c分析
- QT打印
- 开发者成功应聘的二十六条建议
- VCC VDD, VEE, VSS是什么意思
- i2c 总线深入浅出
- 如何在C中使用C++的类
- 裘宗燕:C/C++ 语言中的表达式求值(转自CSDN论坛,C++语言分论坛)
- 3ds MAX画图基础:如何画效果图与鸟瞰图[转]
- DOS中的常见命令
- 我国调整撤销105个国家级非遗保护单位-调整-撤销-非遗
- 菜单自绘,修改弹出菜单样式
- IOS几种简单有效的数组排序方法
- matlab补习之一
- js中的map