简体   繁体   English

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

[英]Passing C++ struct to library expecting C struct

I am writing a C++ program in Linux and need to use an older library written in C. The library uses C structs for passing information in and out of functions, and these structs are byte aligned (no padding). 我正在Linux中编写一个C ++程序,需要使用用C编写的旧库。库使用C结构将信息传入和传出函数,这些结构是字节对齐的(无填充)。

My understanding is that a struct in C++ is actually an object, while a struct in C is just a block of memory divided up into individually addressable pieces. 我的理解是C ++中的结构实际上是一个对象,而C中的结构只是一个内存块,被分成可单独寻址的部分。

How can I create a C style struct in C++ to pass to the library? 如何在C ++中创建C样式结构以传递给库? (I can't pass an object) (我不能传递一个对象)

You're asking two questions here, really... 你在这里问两个问题,真的......

How can I create a C style struct in C++? 如何在C ++中创建C样式结构?

Instead of 代替

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

use 使用

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

This probably won't result in anything different, ie a "C++ style struct" and a "C style struct" are usually the same thing, as long as you don't add methods, protected members, and bit fields. 这可能不会导致任何不同,即“C ++样式结构”和“C样式结构”通常是相同的,只要您不添加方法,受保护的成员和位字段。 Since "extern C" is needed for functions, however, it's reasonable to just surround all code intended for use in C within these braces. 但是,由于函数需要“extern C”,所以在这些大括号中包含所有用于C的代码是合理的。

For more details, read: What is the effect of extern "C" in C++? 有关更多详细信息,请参阅: 外部“C”在C ++中的作用是什么? and @AndrewHenle's comment. 和@AndrewHenle的评论。


I ... need to use a library written in C 我...需要使用用C编写的库

I'm paraphrasing an official C++ FAQ item here, telling you to (surprise, surprise) just include the library header within an extern C block, then use whatever's in it like you would if you were writing C: 我在这里解释一个正式的C ++ FAQ项目 ,告诉你(惊讶,惊讶)只是在一个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);
}

My understanding is that a struct in C++ is actually an object, while a struct in C is just a block of memory divided up into individually addressable pieces. 我的理解是C ++中的结构实际上是一个对象,而C中的结构只是一个内存块,被分成可单独寻址的部分。

You have just described almost the exact same thing, in different words. 你刚才用不同的词语描述了几乎完全相同的东西。

Because of the syntax overlap of both languages, you can usually take a simple class defined with the struct keyword and compile that same definition with a C compiler. 由于两种语言的语法重叠,您通常可以使用struct关键字定义的简单类,并使用C编译器编译相同的定义。

Furthermore, you can usually pass a pointer to an object of a user-defined type from a C++ program, into a C program. 此外,您通常可以将指向用户定义类型的对象的指针从C ++程序传递到C程序。 However you will usually want to wrap the definition in extern "C" in order to tell the computer you want this compatibility. 但是,您通常希望将该定义包装在extern "C"中,以便告诉计算机您希望这种兼容性。

Finally, remember that in C++ the keyword class and the keyword struct both introduce a class definition so C++ doesn't really have "structs", but in C they are most definitely a thing (whereas classes are not). 最后,请记住,在C ++中,关键字class和关键字struct都引入了一个类定义,因此C ++实际上没有“结构”,但在C中它们绝对是一个东西(而类不是)。 As such just be a little careful with the terminology. 因此,只需要小心使用术语。

So, this question has some complex issues associated with it. 所以,这个问题有一些与之相关的复杂问题。 But, to a first approximation, the answer is simple. 但是,对于第一个近似,答案很简单。

Any C struct declaration that will be accepted by both a C compiler and a C++ compiler (which is most of them that are accepted by a C compiler) will be a ' Standard Layout Type '. C编译器和C ++编译器(大多数C编译器都接受它们)将接受的任何C struct声明都将是“ 标准布局类型 ”。 This is a concept defined in the C++ standard, and C++ compilers are supposed to treat them a certain way. 这是C ++标准中定义的概念,C ++编译器应该以某种方式对待它们。

In particular, a C compiler that conforms to a subset of the ABI (aka Application Binary Interface) that a C++ compiler conforms to should have the exact same memory representation for such a type. 特别是,符合C ++编译器符合的ABI(也称为应用程序二进制接口)子集的C编译器应具有与此类型完全相同的内存表示。

For both Linux and Windows, the ABI is very carefully defined for both C and C++ and has been for 5-10 years now. 对于Linux和Windows,ABI都经过了C和C ++的精心定义,现在已经有5到10年了。 All compilers on either platform are supposed to conform to it. 任何平台上的所有编译器都应该符合它。 So this is true for any of the common C and C++ compiler combinations. 所以对于任何常见的C和C ++编译器组合都是如此。 This includes Clang, g++, Visual Studio, and basically practically any compiler that isn't highly specialized that works on that platform. 这包括Clang,g ++,Visual Studio,基本上几乎任何在该平台上都不具备高度专业性的编译器。 This doesn't necessarily mean that different versions of the standard C++ libraries have compatible implementations because (for example) the way ::std::string has been implemented over the years (and therefor what pieces of data are actually in the string structure) has changed drastically even though the public interface hasn't changed much. 这并不一定意味着标准C ++库的不同版本具有兼容的实现,因为(例如)多年来实现::std::string的方式(因此字符串结构中实际存在哪些数据)尽管公共界面没有太大变化,但已经发生了巨大的变化。

The C++ ABI is complicated by a few different factors. C ++ ABI由于一些不同的因素而变得复杂。 Among them being exception handling and function name mangling (encoding the types of function arguments in the linker symbol name for the function) conventions. 其中包括异常处理和函数名称修改(在函数的链接器符号名称中编码函数参数的类型)约定。 Also, because of the way types are defaulted to int in so many situations and other issues, C largely required the caller to pop arguments off the stack after the function finished because the called function couldn't really be sure of the sizes of the arguments that had been pushed on. 此外,由于在很多情况下和其他问题中类型默认为int的方式,C很大程度上要求调用者在函数完成后从堆栈中弹出参数,因为被调用的函数无法确定参数的大小已经被推上了。 C++ has stricter type checking, and for awhile this resulted in a 'called function pops the parameters' calling convention. C ++有更严格的类型检查,有一段时间这导致了一个'被调用函数弹出参数'调用约定。 I don't think this is the case anymore because I think it turned out that it was less efficient. 我认为不再是这种情况了,因为我认为它的效率较低。 I might be wrong though. 我可能错了。

Now, this all goes out the window if you start using compiler-specific keywords like 'packed' or 'aligned'. 现在,如果您开始使用编译器特定的关键字,如'packed'或'aligned',这一切都会消失。 Then, you should carefully consult the documentation to figure out what happens. 然后,您应该仔细查阅文档以了解会发生什么。

People have mentioned an extern "C" declarations. 人们提到了一个extern "C"声明。 These are important for interfacing between C and C++ code, but they have nothing to do with struct layout and are not needed for this at all. 这些对于C和C ++代码之间的接口很重要,但它们与struct布局无关,根本不需要它。 What extern "C" declarations are good for is declaring that function names and calling conventions conform to the C ABI and not the C++ ABI. 什么extern "C"声明是好的,声明函数名称和调用约定符合C ABI而不是C ++ ABI。 This is about whether the caller pops function call parameters off the stack or the called function does, how the function name is turned into a symbol for the linker to work with, the order parameters are pushed on the stack, and so forth. 这是关于调用者是否从堆栈或被调用函数中弹出函数调用参数,函数名称如何变为符号以供链接器使用,订单参数被推入堆栈,等等。 Again, nothing about how structures are layed out in memory has anything to do with extern "C" . 同样,关于结构如何在内存中布局的内容与extern "C"无关。 That construct is all about functions, not struct s. 该构造完全是关于函数,而不是struct

And, to re-iterate, there's a lot of complexity here. 并且,为了重新迭代,这里有很多复杂性。 But in the vast majority of cases, you don't need to worry about it at all. 但在绝大多数情况下,您根本不需要担心它。 It will just work. 它会起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM