GCC可以将类编译为结构体吗?

Can GCC compile classes to work as structs?

本文关键字:结构体 编译 GCC      更新时间:2023-10-16

是否有办法强制编译器(特别是GCC)使类编译为面向对象的C?具体来说,我想要实现的是这样写:

class Foo {
public:
  float x, y, z;
  float bar();
  int other();
  ...etc
};
Foo f;
float result = f.bar()
int obSize = sizeof(Foo);

却编译成完全相同的:

Struct Foo { float x, y, z; };
float Foo_bar(Foo *this);
Foo f;
float result = Foo_bar(&f);
int obSize = sizeof(Foo);

我的动机是提高可读性,但又不为Foo的每个对象遭受内存损失。我想类的实现通常是obSize为

obSize = sizeof(float)*3 + sizeof(void*)*number_of_class_methods

在内存受限的微控制器中主要使用c++类。然而,我想如果我让它工作,我也会用它来进行网络序列化(当然是在相同的端序机器上)。

你的编译器实际上为你做了这些。它甚至可以通过将this指针放在寄存器中而不是将其压入堆栈来优化(这至少是MSVC在Windows上所做的),这在标准的C调用约定中是无法做到的。

:

obSize = sizeof(float)*3 + sizeof(void*)*number_of_class_methods
  1. 这是完全错误的。你试过吗?
  2. 即使有虚函数,每个对象也只能添加一个指向函数表的指针(每个类一个表)。在没有虚函数的情况下,除了对象的成员之外,不会向对象添加任何内容(也不会生成函数表)。
  3. void*表示指向数据的指针,而不是指向代码的指针(它们不需要具有相同的大小)
  4. 不能保证等效C结构体的大小为3 * sizeof(float)

c++已经为你所说的非多态类(没有虚方法的类)做了。

一般来说,c++类将具有与C结构体相同的大小,除非该类包含一个或多个虚方法,在这种情况下,开销将是每个类实例的单个指针(通常称为vptr)。

还将有一个'vtbl'的单个实例,该实例具有每个虚函数的一组指针-但是该vtbl将在所有该类类型的对象之间共享。例如,每个类类型都有一个VTBL,并且该类对象的各种VPTRS将指向同一个VTBL实例)。

总而言之,如果你的类没有虚方法,它将不会大于相同的C结构体。这符合c++不为不用的东西买单的理念。

但是,请注意,c++类中的非静态成员函数确实接受参数列表中没有明确提到的额外参数(this指针)-这实际上是您在问题中讨论的内容。


脚注:在c++中,类和结构是一样的,除了默认成员的可访问性有一点不同。在上面的答案中,当我使用术语"类"时,这种行为同样适用于c++中的结构体。当我使用术语"结构"时,我指的是C结构体。

还要注意,如果你的类使用继承,继承的"开销"取决于继承的确切种类。但是就像多态类和非多态类之间的区别一样,无论成本是多少,它只有在你使用它时才会带来。

不,你的想象错了。类方法在对象中不占用任何空间。为什么不写一个类,然后取sizeof。然后添加更多的方法并再次打印sizeof。你会发现它没有改变。像这样

的第一个程序

class X
{
public:
  int y;
  void method1() {}
};
int main()
{
  cout << sizeof(X) << 'n'; // prints 4
}

第二个程序

class X
{
public:
  int y;
  void method1() {}
  void method2() {}
  void method3() {}
  void method4() {}
  void method5() {}
  void method6() {}
};
int main()
{
  cout << sizeof(X) << 'n'; // also prints 4
}

实际上,我认为使用类没有特定的内存损失,因为成员函数为类的每个实例存储一次。因此,您的内存占用将更像1*sizeof(void*)*number_of_class_methods + N*sizeof(float)*3,其中您有FooN实例。

只有在使用虚函数时才会受到额外的惩罚,在这种情况下,每个对象都携带一个指向虚函数表的指针。

你需要测试,但据我所知,一个类实例做只有存储指针到它的方法,如果说的方法是虚拟的;否则,一个结构和一个类将占用大致相同的内存量(除了不同的编译器所做的不同对齐等)。