说我想要一个带有C链接的结构foo
。我将不透明地在C风格的头文件(foo.h)中声明它:
struct foo;
typedef struct foo foo;
但我想在foo
的实现中使用C ++。假设我希望foo
包含std::vector<int>
。由于C代码无法访问foo
的字段,因此我不明白为什么编译器(或语言标准)应禁止此操作。但是我该怎么做?我可以将extern "C"
放在foo.cc中foo
的实现中吗?
extern "C" {
struct foo {
....
std::vector<int> bar;
}
}
答案 0 :(得分:0)
只要结构的内容是POD(普通旧数据),结构在C和C ++之间是兼容的。如果您将非POD添加到其中,例如您的向量,它不再与C兼容,并且在与memset
或memcpy
等典型C函数一起使用时会导致未定义的行为。非POD成员导致结构的另一个内存布局,它在它的开头获得一个虚拟表以支持继承。
答案 1 :(得分:0)
我最终在C下填充C ++ ......这是它的一般要点。 (另外,让C ++异常解除C堆栈可能会导致C代码出现问题而不知道会发生这样的事情......因此建议在C ++接口函数中执行一些catch(...)
块。)< / p>
lib.h :一个头文件,使用C调用约定声明一些函数,无论它是编译为C还是C ++
#pragma once
#if defined(__cplusplus)
extern "C" {
#endif
/* Looks like a typical C library interface */
struct c_class;
struct c_class *do_init();
void do_add(struct c_class *tgt, int a);
int do_get_size(const struct c_class *tgt);
void do_cleanup(struct c_class *tgt);
#if defined(__cplusplus)
}
#endif
lib.cpp :一个带有几个用C调用约定声明的函数的C ++库
#include "lib.h"
#include <iostream>
#include <vector>
#include <cstdlib>
class Foo
{
std::vector<int> m_vec;
public:
Foo() : m_vec() {}
virtual ~Foo() {}
void add(int a) {
m_vec.push_back(a);
}
int getSize() {
return m_vec.size();
}
};
/* Exposed C interface with C++ insides */
extern "C" {
struct c_class
{
Foo *guts;
};
struct c_class *do_init()
{
struct c_class *obj = static_cast<c_class*>(malloc(sizeof(struct c_class)));
obj->guts = new Foo();
return obj;
}
void do_add(struct c_class *tgt, int a) {
tgt->guts->add(a);
}
int do_get_size(const struct c_class *tgt) {
return tgt->guts->getSize();
}
void do_cleanup(struct c_class *tgt) {
delete tgt->guts;
free(tgt);
}
}
main.c :使用从lib导出的C调用约定函数的C程序
#include <stdio.h>
#include "lib.h"
int main(int argc, char *argv[])
{
int i;
struct c_class *obj;
obj = do_init();
for(i = 0; i< 100; i++)
{
do_add(obj, i);
}
printf("Size: %d\n", do_get_size(obj));
do_cleanup(obj);
}
Makefile :将C构建为C,将C ++构建为C ++的makefile,然后使用C ++编译器进行链接
CXXFLAGS ?= -Wall -Werror -pedantic
CFLAGS ?= -Wall -Werror -pedantic
.PHONY: all
all : test
test: lib.o main.o
$(CXX) $(CXXFLAGS) -o test lib.o main.o
lib.o: lib.cpp lib.h
$(CXX) $(CXXFLAGS) -c $< -o $@
main.o: main.c lib.h
$(CC) $(CFLAGS) -c $< -o $@
clean:
-rm lib.o main.o test
<强>输出强>:
$ make
g++ -Wall -Werror -pedantic -c lib.cpp -o lib.o
cc -Wall -Werror -pedantic -c main.c -o main.o
g++ -Wall -Werror -pedantic -o test lib.o main.o
$ ./test
Size: 100
答案 2 :(得分:0)
结构本身只是一种类型,换句话说,一种语法糖,除了编译之外不存在作为结构,但只是内存中的几个字节和指向它的指针。因此它没有任何特定于语言的链接。字节的含义由编译器在编译时定义,并且在那里也创建对它们的引用。因此,它的布局取决于您使用的语言。
回答你的问题,std :: vector实现包含某些字段,这些字段成为struct layout的一部分。 c ++理解它们,因为它理解模板和所有其他面向对象的东西,'c'将首先在模板上以及其他c ++ sness上扼制。因此,如果您使用非POD数据,则结构定义不兼容。
如果您使用POD,标准'c'数据类型,没有成员函数和没有位字段,您应该在定义中设置和兼容。这意味着两个编译器都将编译结构,并且布局将类似,以便您可以跨语言保存/恢复它。
如果你所说的只是通过'c'代码将指针传递给c ++结构,那么你应该在任何情况下全部设置。您可以使用强制转换为'void *'以标准方式执行此操作。