【问题标题】:C struct initialization done "recursively"C 结构初始化“递归”完成
【发布时间】:2018-02-21 09:13:55
【问题描述】:

我最近遇到了 this question 解释的 C-struct 初始化示例。

我不明白的是什么似乎是递归定义;这是来自MicroPython/objtype.c

typedef struct _mp_obj_type_t mp_obj_type_t;

const mp_obj_type_t mp_type_type = { // <-- SAME SYMBOL DEFINED HERE . . .
    { &mp_type_type }, // <-- IS USED HERE
    .name = MP_QSTR_type,
    .print = type_print,
    .make_new = type_make_new,
    .call = type_call,
    .unary_op = mp_generic_unary_op,
    .attr = type_attr,
};

.&lt;some_field&gt;指定的字段我明白了(见第一句的链接)。

但是关于“递归”初始化呢?

MicroPython code 中还有其他使用这种语法的实例:

const mp_obj_type_t pyb_led_type = {
    { &mp_type_type }, <-- SAME SYMBOL AS ABOVE
    .name = MP_QSTR_LED,
    .print = led_obj_print,
    .make_new = led_obj_make_new,
    .locals_dict = (mp_obj_t)&led_locals_dict,
};

这更有意义:struct pyb_led_type 使用 struct mp_type_type 中设置的默认值进行初始化,并且某些字段已更改为默认值。

但是const mp_obj_type_t mp_type_type 呢?

结构 mp_type_type 默认为 . . .结构mp_type_type 。 . . ???

预处理后的输出与.c相同。

这里发生了什么?

这是结构体的几个字段

struct _mp_obj_type_t {
    // A type is an object so must start with this entry, which points to mp_type_type.
    mp_obj_base_t base;

    // The name of this type.
    qstr name;

    // Corresponds to __repr__ and __str__ special methods.
    mp_print_fun_t print;

    ...
};
struct _mp_obj_base_t {
    const mp_obj_type_t *type MICROPY_OBJ_BASE_ALIGNMENT;
};
typedef struct _mp_obj_base_t mp_obj_base_t;

【问题讨论】:

  • 其他值没有默认值。 mp_obj_type_t 中的一个字段是一个指针,它是用指针​​值初始化的。
  • 同:void * p = &amp;p;
  • @melpomene 要明确:您是说第一个语句 {&amp;mp_type_type} 只是分配给struct _mp_obj_type_t 类型的第一个成员?
  • struct _mp_obj_type_t 的定义是什么?这似乎是在创建一个包含指向自身的指针以供某些用途的结构。我很好奇它是如何被使用的,为什么会有这种指向自我的指针。我想不出为什么这个特殊的自引用对象会有用,但这可能是由于我缺乏想象力。
  • @Adrian 好吧,大概第一个成员是另一个结构,因此附加了大括号。

标签: c gcc struct


【解决方案1】:

C 中的自引用结构

您引用的 MicroPython 代码只是创建一个自引用结构实例,这在 C 中非常好。考虑这个示例,您的示例几乎去掉了一些不必要的部分:

#include "stdio.h"

// const base
struct A {
    const struct A* base;
};

// non-const base
struct B {
    const struct B* base;
};

const struct A a = { &a };

const struct B b = { &b };

int main() {
    printf("%p %p\n", (void*) &a, (void*)a.base);
    printf("%p %p\n", (void*) &b, (void*)b.base);
    return 0;
}

MicroPython代码中mp_obj_type_t结构体实例化的具体使用

MicroPython 项目正在使用base 指针在Python 中实现(多重)继承base 引用是指向另一种类型的指针,该类型是基本类型(类型层次结构中的“父”),查看definition of this struct

struct _mp_obj_type_t {
    // A type is an object so must start with this entry, which points to mp_type_type.
    mp_obj_base_t base;
   // .. many more fields
}

您提到的情况是mp_type_type const 变量似乎是所有类型的基类型,因此是自引用,但是当您查看从mp_type_type“继承”的类型时,它更有意义,例如pyb_led_type:

const mp_obj_type_t pyb_led_type = {
    { &mp_type_type },
    .name = MP_QSTR_LED,
    .print = led_obj_print,
    .make_new = led_obj_make_new,
    .locals_dict = (mp_obj_t)&led_locals_dict, };

【讨论】:

    【解决方案2】:

    本系统(MicroPython)中的对象以指向其类型的指针开始。 MicroPython 类型表示为 mp_type_type 类型的对象。 mp_type_type 本身就是一个类型,因此它的类型字段指向它自己。 (这个概念也许在 Smalltalk 文献中得到了最好的说明。cf: http://pharo.gforge.inria.fr/PBE1/PBE1ch14.html 也许。)

    【讨论】:

      【解决方案3】:
      const mp_obj_type_t mp_type_type = { // <-- SAME SYMBOL DEFINED HERE . . .
          { &mp_type_type }, // <-- IS USED HERE
          .name = MP_QSTR_type,
      

      ...

      };
      

      指定的字段。我明白(请参阅第一个链接 句)。

      但是关于“递归”初始化呢?

      没有什么可以合理地描述为递归初始化。那将是用该对象的 初始化一个对象或其成员之一,这确实是 C 所禁止的,但没有这样的证据。

      您的示例显示了使用该对象的 地址 初始化的对象的成员(这是&amp; 运算符计算的内容)。对象的地址不依赖于该对象的值,并且可以在对象初始化之前安全地计算出来。在一般意义上,这种做法甚至并不少见,尽管用指向该对象的指针专门初始化对象的一部分是不寻常的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-12-21
        • 2012-07-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多