I've newly come across an example of C-struct initialization that was explained by this question.
What I don't understand is what appears to be recursive definition; this is from 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,
};
The fields specified by .<some_field>
I understand (see link in first sentence).
But about the "recursive" initialization?
There are other instances in the MicroPython code that use this syntax:
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,
};
This makes more sense: the struct pyb_led_type
is initialized with defaults set in struct mp_type_type
and certain fields are changed from the default.
But what about const mp_obj_type_t mp_type_type
?
The struct mp_type_type
is defaulted to the values of . . . struct mp_type_type
. . . ???
The pre-processed output is identical to .c
.
What's going on here?
Here's few fields of the 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;
// 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;
The MicroPython's code you are quoting is simply creating a self-referential struct instance, which is perfectly fine in C. Consider this example, which is pretty much you example stripped of some unnecessary parts:
#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;
}
mp_obj_type_t
structs in MicroPython's codeMicroPython project is using base
pointer to implement (multiple) inheritance in Python. The base
reference is a pointer to another type which is a base type ("parent" in the type hierarchy), looking at the 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
}
The case you are mentioning is mp_type_type
const variable seems to be base type of all types, thus the self-reference but it makes much more sense when you look at the types that "inherit" from mp_type_type
, like 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, };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With