将C风格的 struct 与带有‘Members’函数的C++类进行比较,试图对C++开销进行建模,我怀疑下面的实现将通过包含相同数量的指令而大致等价.我看到当调用‘Members’函数时,C实现会导致额外的指令.

int main()
{
    uint32_t a;
    rectangle_t r;
    
    /* struct */
    r.set(2,3, &r);
    /* asm 
       ldr     r3, [r7, #12]
       adds    r2, r7, #4
       movs    r1, #3
       movs    r0, #2
       blx     r3
    */

    a = r.getArea(&r);
    /* asm 
       ldr     r3, [r7, #16]
       adds    r2, r7, #4
       mov     r0, r2
       blx     r3
       str     r0, [r7, #20]
       movs    r3, #0
    */

    # Class
    r.set(2, 3);
    /* asm 
       adds    r3, r7, #4
       movs    r2, #3
       movs    r1, #2
       mov     r0, r3
       bl      rectangle_t::set(unsigned int, unsigned int)
    */
    a = r.getArea();
    /* asm 
       adds    r3, r7, #4
       mov     r0, r3
       bl      rectangle_t::getArea()
       str     r0, [r7, #12]
       movs    r3, #0
    */
}

为什么在调用 struct ‘Members’而不是类成员时会有额外的LDR指令?

编译:ARM GCC 12.2.0(LINUX)

声明:

typedef struct rectangle rectangle_t;
struct rectangle
{
    uint32_t w;
    uint32_t l;
    void (*set)(uint32_t L, uint32_t W, rectangle_t *self);
    uint32_t (*getArea)(rectangle_t *self);    
};
void set(uint32_t L, uint32_t W, rectangle_t *self)
{
    self->w = W;
    self->l = L;
}

uint32_t getArea(rectangle_t *self)
{
    return self->l * self->w;
}

class rectangle_t
{
public:   

    uint32_t w;
    uint32_t l;  
    void set(uint32_t L, uint32_t W);
    uint32_t getArea(); 
};

void rectangle_t::set(uint32_t L, uint32_t W)
{
    w = W;
    l = L;
}

uint32_t rectangle_t::getArea()
{
    return l * w;
}

推荐答案

在C++中,我们可以声明函数类型的 struct 和/或类成员,给定类的一个实例,就可以访问这些函数.

然而,在C中,我们不能有函数类型的字段,所以,你所做的就是函数指针.这样,这些字段就是真的variables-instance个变量--任何人都可以动态赋值给它,这就是开销的来源(除非编译器能看到优化,否则必须参考变量的值;与任何字段变量一样,同一 struct 的不同实例也可以有不同的值).请注意,您还没有显示函数指针的初始化-在某个地方,您必须 for each 单独的 struct 实例执行r.set = set; r.getArea = getArea;,否则您将得到垃圾或零,这取决于用于 struct 的存储.

要使C代码"有点"等价,就必须创建函数,而不是函数指针,并且,它们必须声明在struct之外,因此,与C++相比,有效地分离了.

C++相关问答推荐

错误:C中需要参数声明符

在C中使用强制转换将uint16_t转换为uint8_t [2]是否有效?

如何在C中使printf不刷新标准输出?

X64:并发写入布尔数组

从uint8_t*转换为char*可接受

在C++中允许使用字符作为宏参数

错误...的多个定义(&Q)首先在这里定义&

如果格式字符串的内存与printf的一个参数共享,会发生什么情况?

静态初始化顺序失败是否适用于C语言?

int * 指向int的哪个字节?

从另一个宏函数调用C宏

如何在C中处理流水线中的a、n命令?

按字典顺序打印具有给定字符的所有可能字符串

在分配内存后使用指针是未定义的行为吗?

当另一个指向 const 的指针观察到数据时,通过指针更改数据是否安全?

使用 c 中的 write() 函数将非 ASCII 字符写入标准输出

std::malloc/calloc/realloc/free 与纯 C 的 malloc/calloc/realloc/free 有什么不同

子进程不会修改父进程中的统计信息

Codewars Kata 掷骰子的不稳定行为

React Native Android C++ TurboModules 静态 C 库链接问题