C initialization of the C structure "recursively"

I recently came across an example of C-structure initialization, which was explained by this question .

What I do not understand is a 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, }; 

Fields specified .<some_field> , I understand (see link in the first sentence).

But about "recursive" initialization?

There are other examples in 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 sense: the pyb_led_type structure pyb_led_type initialized with the default values ​​specified in struct mp_type_type , and some fields change from the default value.

But what about const mp_obj_type_t mp_type_type ?

The string mp_type_type defaults to., mp_type_type ., ???

The pre-processed output is identical to .c .

What's going on here?

There are several structure fields

 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; 
+5
source share
3 answers

Self-regulatory structures in C

MicroPython code coding is just creating an instance of a self-referential struct that works great for C. Consider this example, which pretty much you 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; } 

Specific use when creating mp_obj_type_t structures in MicroPython code

The MicroPython project uses the base pointer to implement (multiple) inheritance in Python. The base reference is a pointer to another type, which is the base type ("parent" in the type hierarchy), considering the definition of this structure :

 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 mention is the mp_type_type const variable, apparently, is the basic type of all types, so it’s self-aware, but it makes sense when you look at types that “inherit” from mp_type_type , for example 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
source

Objects on this system (MicroPython) begin with a pointer to their type. MicroPython types are represented as objects of type mp_type_type. The type mp_type_type is a type, so its type field points to itself. (The concept is perhaps best illustrated in the Smalltalk literature. Cf: http://pharo.gforge.inria.fr/PBE1/PBE1ch14.html is possible.)

0
source
 const mp_obj_type_t mp_type_type = { // <-- SAME SYMBOL DEFINED HERE . . . { &mp_type_type }, // <-- IS USED HERE .name = MP_QSTR_type, 

...

 }; 

Fields specified. I understand (first see the link sentence).

But about "recursive" initialization?

There is nothing that could be described as recursive initialization. This will be the initialization of an object or one of its members by the value of this object, which C really prohibits, but this has not been proved.

Your example shows a member of an initialized object with the address of that object (as calculated by the & operator). The address of the object in no way depends on this value of the object, and it can be safely calculated before the object is initialized. This practice is not even so unusual in the general sense, although it is unusual to specifically initialize a part of an object with a pointer to that object.

-1
source

Source: https://habr.com/ru/post/1271742/


All Articles