将C ++结构传递给期望C结构的库

时间:2018-04-08 22:28:10

标签: c++ c linux struct

我正在Linux中编写一个C ++程序,需要使用用C编写的旧库。库使用C结构将信息传入和传出函数,这些结构是字节对齐的(无填充)。

我的理解是C ++中的结构实际上是一个对象,而C中的结构只是一块内存,被分成可单独寻址的部分。

如何在C ++中创建C样式结构以传递给库? (我不能传递一个对象)

3 个答案:

答案 0 :(得分:5)

你在这里问两个问题,真的......

  

如何在C ++中创建C样式结构?

而不是

struct foo { /* ... */ };

使用

extern "C" {
    struct foo { /* ... */ };
}

这可能不会导致任何不同的结果,即" C ++风格的结构"和一个" C风格的结构"通常是相同的,只要你不添加方法,受保护的成员和位字段。因为" extern C"但是,在这些大括号中包含所有用于C语言的代码是合理的。

有关详细信息,请参阅:What is the effect of extern "C" in C++?和@ AndrewHenle的评论。

  

我...需要使用用C语言编写的库

我在这里解释一个official C++ FAQ item,告诉你(惊讶,惊讶)只是将库标题包含在一个extern C块中,然后使用其中的任何内容,就像你想要的那样正在写C:

extern "C" {
  // Get declaration for `struct foo` and for `void f(struct foo)`
  #include "my_c_lib.h"
}

int main() {
    struct foo { /* initialization */ } my_foo;
    f(my_foo);
}

答案 1 :(得分:1)

  

我的理解是C ++中的结构实际上是一个对象,而C中的结构只是一块内存,被分成可单独寻址的部分。

你刚才用不同的词语描述了几乎完全相同的东西。

由于两种语言的语法重叠,您通常可以使用struct关键字定义一个简单的类,并使用C编译器编译相同的定义。

此外,您通常可以将指向用户定义类型的对象的指针从C ++程序传递到C程序。但是,您通常希望将定义包装在extern "C"中,以便告诉计算机您希望这种兼容性。

最后,请记住,在C ++中,关键字class和关键字struct都会引入类定义,因此C ++并没有真正拥有"结构& #34;,但在C中它们绝对是一个东西(而类不是)。因此,只需要小心使用术语。

答案 2 :(得分:0)

所以,这个问题有一些与之相关的复杂问题。但是,对于第一个近似,答案很简单。

C编译器和C ++编译器(大多数C编译器都接受)将接受的任何C struct声明将是' Standard Layout Type &#39 ;.这是C ++标准中定义的概念,C ++编译器应该以某种方式对待它们。

特别是,符合C ++编译器符合的ABI (aka Application Binary Interface)子集的C编译器应具有与此类型完全相同的内存表示。

对于Linux和Windows,ABI都经过了C和C ++的精心定义,现在已经有5到10年了。任何平台上的所有编译器都应该符合它。所以对于任何常见的C和C ++编译器组合都是如此。这包括Clang,g ++,Visual Studio,基本上几乎任何在该平台上都不具备高度专业性的编译器。这并不一定意味着标准C ++库的不同版本具有兼容的实现,因为(例如)多年来实现::std::string的方式(因此,字符串结构中实际存在哪些数据) )即使公共界面没有太大变化,也发生了巨大的变化。

C ++ ABI因一些不同因素而变得复杂。其中包括异常处理和函数名称修改(在函数的链接器符号名称中编码函数参数的类型)约定。另外,由于在很多情况和其他问题中类型默认为int的方式,C很大程度上要求调用者在函数完成后从堆栈中弹出参数,因为被调用的函数无法确定已推出的参数的大小。 C ++有更严格的类型检查,有一段时间,这导致一个被调用的函数弹出参数'召集会议。我不认为这种情况已经存在了,因为我认为事实证明效率较低。我可能错了。

现在,如果您开始使用编译器特定的关键字,例如' packed'或者'对齐'然后,您应该仔细查阅文档以了解会发生什么。

人们提到了extern "C"声明。这些对于C和C ++代码之间的接口很重要,但它们与struct布局无关,根本不需要它。 extern "C"声明的优点是声明函数名和调用约定符合C ABI而不符合C ++ ABI。这是关于调用者是否从堆栈或被调用函数中弹出函数调用参数,函数名称如何变为符号以供链接器使用,订单参数被推入堆栈,等等。同样,关于结构在内存中如何布局的任何内容都与extern "C"无关。该构造完全与函数有关,而不是struct s。

而且,为了重新进行迭代,这里有很多复杂性。但在绝大多数情况下,你根本不需要担心它。它会起作用。