qemu源码分析(6)--Apple的学习笔记
  2Nv1H5BMjysw 2023年11月02日 27 0

一,前言

由于看到了类似的写法,都用到了object_dynamic_cast_assert函数,所以分析下。

二,源码分析

  1. 看到如下代码的写法,很眼熟
CortexMBoardState *board = CORTEXM_BOARD_STATE(machine);

machine 的类型是MachineState *

#define CORTEXM_BOARD_STATE(obj) \
 OBJECT_CHECK(CortexMBoardState, (obj), TYPE_CORTEXM_BOARD)
 
#define OBJECT_CHECK(type, obj, name) \
 ((type *)object_dynamic_cast_assert(OBJECT(obj), (name), \
 __FILE__, __LINE__, __func__))
  1. 展开后就是
    ((CortexMBoardState *)object_dynamic_cast_assert(((Object *)((machine))), ("cortexm:" "machine"), __FILE__, __LINE__, __func__))
  2. 主要分析object_dynamic_cast_assert函数
Object *object_dynamic_cast_assert(Object *obj, const char *typename,
 const char *file, int line, const char *func)
{
……
inst = object_dynamic_cast(obj, typename);
……
}
Object *object_dynamic_cast(Object *obj, const char *typename)
{
 if (obj && object_class_dynamic_cast(object_get_class(obj), typename)) {
 return obj;
 }
 
 return NULL;
}
  1. 所以最主要的是object_class_dynamic_cast函数
ObjectClass *object_class_dynamic_cast(ObjectClass *class,
 const char *typename)
{
……
  /* 根据name直接找class */
 type = class->type;
 if (type->name == typename) {
 return class;
   }
/* 根据name来找到Type */
target_type = type_get_by_name(typename);
 if (type->class->interfaces &&
 type_is_ancestor(target_type, type_interface)) {
 ……
}
/* 根据父类的name来找type */ 
else if (type_is_ancestor(type, target_type)) {
 ret = class;
 }
}

上面我加的注释其实描述的不对,应为用了找class,其实class是传入的参数,是通过object_get_class(obj)传入的obj->class,而object是应用层machine将类型MachineState*强转为object*的。所以这里不能说找class,只能说check class。所以从宏定义的名字OBJECT_CHECK也看出这个函数的含义是检查用的。

若我不检查,直接CortexMBoardState *board = CortexMBoardState *)machine来赋值也可以,但是添加check就可以检查object或父类的object是否匹配,避免错误。

至于可以强转的原因是machine可以理解为是CortexMBoardState的父类。


typedef MachineState CortexMBoardParentState;

typedef struct {

    // private:

    CortexMBoardParentState parent_obj;   //子类中首个成员包含了父类

    // public:


    BoardGraphicContext graphic_context;


} CortexMBoardState;


//父类
MachineState *machine

三,小结

这种就类似c++中的基类转为派生类,说不定c++源码的实现也是这样的设计,又学习到一招,这就是我喜欢底层的原因,因为能更加深入的了解设计方法及运行机制。


补充:子类的创建都没malloc,都是从父类object中获取的指针,说明父类object创建的时候就已经malloc好了子类的而内存空间,所以子类的赋值才需要先获取父类的指针。

举例

DeviceClass *dc =DEVICE_GET_CLASS(dev);

接着就直接读取dc->realize的成员内容了。原因是.class_size在申请内存空的时候已经预留了子类DeviceClass的内存空间。

static
const TypeInfo stm32_mcu_type_info = {
    .abstract = true,
    .name = TYPE_STM32_MCU,
    .parent = TYPE_STM32_MCU_PARENT,
    .instance_init =
stm32_mcu_instance_init_callback,
    .instance_size = sizeof(STM32MCUState),
    .class_init =
stm32_mcu_class_init_callback,
    .class_size = sizeof(STM32MCUClass)
/**/
};

所以看下class_size是否包括了DeviceClass的结构体size,果然有的。

STM32MCUClass

  CortexMClass

    SysBusDeviceClass

         DeviceClass

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

上一篇: Lua06——Lua表达式 下一篇: 复习课7 常量
  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

2Nv1H5BMjysw