分解通信:传递C风格结构与C 对象
Interprocess communication: passing C-style structs vs C++-objects
警告/免责声明:
这个问题包含HERESAY,但是在过去半小时左右的我的小研究中,我找不到下面所述主张的答案。我很好奇,如果这里有人已经知道这一点。
这个问题没有代码。只是技术查询。
背景:
我有一个旧应用程序,该应用程序使用 cransCess Communication 的过程之间传递的C风格结构。而且这种运作良好,并且已经工作了很多年,即使我在这个星球上也很早就:p。
我应该写一个将成为本应用程序的一部分的新过程。不知不觉地,我在C 上写了它,假设Whaterver IPC,我们正在使用它可以处理的。不幸的是,然后我(来自同事)发现现有的基础架构只能通过C风格的结构。
'未验证'索赔/语句:
此外,其中一个同事列出了C 在这种情况下是不良选择的以下原因。
-
c 对象具有VTABLES。C风格的结构只是变量和值。因此,C型结构可以围绕进程传递,而C 对象则不能。
-
使用C风格的结构,我们可以嵌入诸如结构的大小之类的信息,以便双方都知道期望什么和发送什么,但是对于C 对象,这是不可能的VTable可以变化'。
-
'如果我们更改编译器,那么情况甚至更糟。对于C 对象,我们将需要更多的排列。'
调查索赔:
不必说,这个同事对C有一点偏见,但他比我经验丰富,并且可能知道他在说什么。我是语言 - 敏捷。但这立即让我思考。我们怎么不能与C 进行反学交流?我搜索了谷歌搜索,最初的命中总是来自Stackoverflow,就像这样:
过程间通信建议
我查看了此处列出的IPC的不同方法。https://en.wikipedia.org/wiki/inter-process_communication#apphaches
我的意思是,我跟进了列表中的每种方法,例如管道或共享内存等,而每个人都一直指出的唯一警告是,指示器(当然是duh!)不能像这样传递同步的某些问题可能会蔓延 - je nachdem。
但是,我找不到可以反驳或证实他的"主张"的东西。(当然,我可以继续挖掘一天的剩余时间。:P)
问题:
-
他的三个主张真的如此还是只是FUD?考虑到这一点,我想要传递的那些对象中所拥有的所有内容也只有POD变量和某些STL容器(例如
std::vector
和std::pair
)及其值及其值(没有指针或任何东西),以及这些变量的Getters。没有虚拟函数除了虚拟驱动器,它存在于我从一个基本消息类中继承所有消息以来存在,因为当时我认为可能有一些常见的基本功能。(我现在可以很容易地摆脱这个基础,因为到目前为止,没有真正常见的东西!值得庆幸的是,出于某种原因,我在单独的班级中保留了消息的解析和格式。运气或远见?:D) -
它实际上也让我感到奇怪,编译器如何知道struct何时是C风格的结构,因为我们正在为整个项目使用G 编译器?是"虚拟"关键字的使用?
-
我不是要为我的案件提供解决方案。我可以将这些对象的结果包裹在结构中,并通过IPC将它们传递给它们,或者我可以摆脱基础类别和虚拟破坏者,如上面的"我的"点1"中所述。
提升或任何C 11的内容或任何处理此操作的库。这方面的任何建议都与手头的问题相切。
(P.S。现在我发布并重新阅读了我的发布的内容,我想在任何阅读此书的读者的头脑中逐渐蔓延的想法,而不是因为与那个同事争论。怀疑是好的,但是如果我们都假设其他人有良好的意图,对社区会很好。:))
只有每个人都一直指出的只是警告,这是,当然不能像这样的指针(当然)
指针值(以及对内存和资源的其他引用)确实在整个过程中都毫无意义。这显然是虚拟内存的结果。
另一个警告是,当C标准指定结构的精确(平台特定)内存布局,C 标准不能保证一般类的特定内存布局。例如,一个过程不一定与成员之间的填充量(即使在同一系统中)的另一个过程一致。C 仅保证标准布局类型的内存布局 - 这可以保证与C结构匹配。
...还有一些STL容器,例如STD :: vector ...(没有指针或其他任何东西)
除std::array
外,所有标准容器都在内部使用指针。他们之所以这样做是因为它们的大小是动态的,因此必须动态分配数据结构。另外,这些都不是标准布局类。此外,不能保证一个标准库实现的类定义与另一个实现匹配,并且两个过程可以使用不同的标准库 - 这在Linux上根本不常见,在Linux上,某些过程可能会使用libstdc (来自GNU),而另一些过程可能会使用libc (来自clang)。
没有虚拟函数除了虚拟驱动器
换句话说:至少有一个虚拟函数(destructor),因此有一个指针 vtable。而且由于具有虚拟函数的类绝不是标准布局类,因此也无法保证内存布局。
所以回答问题:
-
主要不是FUD,尽管从技术上讲有些说法有点不准确:
- C 对象 May 具有vtables;并非所有人都这样做。C结构可以有指针,因此并非所有C结构都可以共享。某些C 对象可以共享累积过程。具体来说,可以共享标准布局类(假设没有指针)。
- 实际上无法共享带有VTABLES的对象。
- 标准布局类具有保证的内存布局。只要您将自己限制在标准布局类中,更改编译器就不是问题。如果您不幸的话,试图分享其他课程可能会显得有效,但是当您开始混合编译器时,您可能会遇到问题。
-
C Stadard定义了类是标准布局的确切条件。所有C结构定义都是C 中的标准布局类。编译器知道这些规则。
-
这不是一个问题。
结论:您 can 将C 用于IPC,但您仅限于该接口中的标准布局类。这使您不包括许多C 功能,例如虚拟函数,访问说明器等。但不是全部:您仍然可以具有成员功能。
确实要注意,使用C 功能可能会导致相互处理接口仅与C 一起使用。许多语言可以与C接口,但几乎没有任何语言可以与C 接口。
此外:如果您的"分解"通信超出了系统的边界 - 跨网络 - 即使是C结构或标准布局类也不是一个好的表示。在这种情况下,您需要序列化。
- 他的三个主张真的是如此还是只是FUD?考虑到这一点,我想要传递的那些物体中所拥有的一切也只有POD变量和某些STL容器(例如STD :: vector :: vector and std :: Pair及其值及其值(没有指针或任何东西)以及Getters对于这些变量。除了虚拟驱动器之外,没有虚拟函数,该功能是因为我从一个基本消息类中继承了所有消息以来存在,因为当时我认为可能存在一些共同的基本功能。(我现在可以很容易地摆脱这个基础,因为到目前为止,没有真正常见的东西!值得庆幸的是,出于某种原因,我保留了单独的班级解析和格式化。运气或远见?:D)
否,一旦STL容器在您的结构中,就无法像Pod数据一样传递它们。未指定STL容器的实现,它们可能(在大多数情况下)包含用于内部目的的指针。
- 它实际上也让我感到奇怪,编译器如何知道构成何时是C风格的结构,因为我们正在为整个项目使用G 编译器?是"虚拟"关键字的使用?
只要您的struct/class只有pod数据,并且没有虚拟功能,它将被存储为pod,但是如果与另一个编译器和/或不同的编译器一起编译了IPC的另一侧,则对齐差异可能是一个问题。设置或不同的对齐指令(例如#Pragma Pack等)。
- 我不是要求解决我的案子的解决方案。我可以将这些对象的结果包裹到结构中,并通过IPC将它们传递给它们,或者我可以摆脱基础类别和虚拟破坏者,如上面的"我的"点1"中所述。
将这些对象的结果包裹到结构中,并通过IPC传递它们对我来说听起来不错,这就是我要做的。另一个解决方案也不错,很难说出哪个没有上下文。
'未验证'索赔/语句:
C 对象具有VTABLES。C风格的结构只是变量和值。因此,C型结构可以围绕过程传递,而C 对象则不能。
此陈述部分是正确的,但以误导性的方式施放。
并非所有的C 对象都具有VTABLES(从技术上讲,C 标准根本不需要VTABLES,尽管它是用于支持虚拟函数调度的常见实现技术,因为它提供了各种优势)。
。如果您查找了这个问题,并且各种答案,您将在C 中找到有关聚合和POD类型的讨论。捕获的是,C 标准之间的定义(如该问题的各种答案所反映)。在C 11中,更改了POD类型的概念,并有效地用微不足道和标准的类型的概念代替。
pod类型(C 11之前)和标准layout类型(C 11及更高版本)可以在C 和C之间互换(即,从用一种语言编写的代码传递给另一种语言的代码,因为内存布局兼容)。
的确,具有任何虚拟函数的C 对象是不能与C互换的C 对象,通常无法复制Pointer,这阻止了(大多数)C 标准容器的使用。
使用C风格结构,我们可以嵌入信息,例如大小 结构,以便双方都知道期望什么和发送什么,但是 对于C 对象,这是不可能的 可能会有所不同。
此语句是错误的,因为有一些类型没有VTable,并且可以在C 和C。
之间互换的类型如果我们更改编译器,那就更糟了。对于C 对象,我们将有更多的排列要处理。
再次,只要在C 代码中正确选择类型,就可以与c。
互换此语句 - 与C与C 互操作的情况也是如此。对于C,C类型的大小正式在C中正式实现,就像在C 中一样。int
,long
,float
,double
之类的类型不能保证具有不同编译器的大小相同。有一些编译器的设置会改变某些或所有基本类型的大小(例如,具有不同浮点选项的编译器,具有设置的编译器会影响int
是16还是32位,等等)。
struct
c中的类型在成员之间也可能具有填充,填充物在C编译器之间可能会有所不同。许多编译器具有影响填充的编译选项,这会影响struct
类型的大小。这可以在c。
struct
类型的布局不兼容那么这里可能发生了什么?
概要通信的设计可能是在使用相同(或兼容)编译器构建的C代码之间的假设。IPC机制可能很简单:例如,一个过程在指定的内存位置在管道下挤出一定数量的数据,而接收器将该管道另一端接收到的数据复制到等效的数据结构中。p>隐含的假设是可以直接复制数据。这依赖于两个程序中兼容的数据类型的布局。
问题在于,由于IPC机制是用兼容C编译器的假设设计的,因此您现在被告知这是由于C优于C (或其他语言)的优势。它不是。这是如何完成IPC的人工制品。
IPC方法可能非常有限,但是您的C 代码可以通过IPC机制发送和接收数据,只要您将数据包装在C 代码中的适当类型(例如标准layout)中。而其他过程是用C或C 编写的。它可能需要在C 中进行更多的工作(例如,将C 类的数据包装成标准的结构结构,并向另一个过程喷压到该结构 - 或者如果接收到数据的相反),但这肯定是可能的。
>无论如何,您都需要使用兼容的编译器。
这是假设您不能更改分解通信的手段(例如,设计用于在过程之间进行交谈的协议,而不是盲目地从内存位置沿线复制数据到另一个过程,然后接收过程复制数据回到兼容的数据结构中)。有一些方法可以做IPC,如果需要,可以更好地支持一系列编程语言 - 尽管具有不同的权衡取舍(例如,通信的带宽,代码可以转换数据,以便将其发送,以及代码以接收数据并转动数据返回数据结构)。
- 为什么我们再次从结构对象创建结构变量?
- 在什么情况下,两个堆栈分配的结构对象的 this 点指向同一个地址?
- 结构对象的指针成员在传递给函数时被修改
- C++ 提升 - 包含类层次结构对象的类的序列化
- 如何将变量从变量传递到指针结构对象
- 在 boost::heap::p riority_queue 中推送结构对象时出错
- 在 c++ 中将结构的每个成员写入文件和将结构对象直接写入文件之间有什么区别吗?
- 为什么结构对象不是类型?
- 程序不会编译,使用带有结构对象的数组
- 在类构造函数中初始化自定义结构对象的正确方法
- 使用QString或字符串调用结构对象
- 在输入结构对象的输入过程中运行时间错误
- C 中的堆是否包含类和结构对象,或者仅包含指针
- 如何将部分初始化的结构对象放入向量
- 如何分配给结构对象的成员
- 尝试创建结构对象,在位置0x3FE00000中创建访问冲突写入错误
- erase() 不适用于结构/对象内的 STL 向量
- 将指向参数个数可变的函数的指针存储在结构对象中
- 如何通过先前存储的ID从结构对象中检索值?C
- 非结构对象布局