neo1218 neo1218 - 4 years ago 125
Python Question

Is this a circular definition in cpython?

I was reading cpython source code and I am confused about these PyXXXObject,
screen shot 2017-02-05 at 16 55 52

I think there is a circular definition




it work !

#include <stdio.h>
#include <stdlib.h>

typedef struct _object {
struct _typeobject *ob_type; // because it's a pointer!
} PyObject;

typedef struct {
PyObject ob_base;
} PyVarObject;

#define PyObject_VAR_HEAD PyVarObject ob_base;

typedef struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name;
} PyTypeObject;

int main(int argc, char **argv) {
PyVarObject var;

return 0;
}

Answer Source

The defines are not actually evaluated until they are used so:

typedef struct {
    PyObject_VAR_HEAD
} PyVarObject;

Is expanded to:

typedef struct {
    PyObject_HEAD 
    Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;

And PyObject_HEAD is defined as well so the above expands to:

typedef struct {
    _PyObject_HEAD_EXTRA
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
    Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;

and _PyObject_HEAD_EXTRA is also a macro which depending on your compile time settings is either nothing or:

struct _object *_ob_next;
struct _object *_ob_prev;

So the declaration of PyVarObject becomes one of:

typedef struct {
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
    Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;

or:

typedef struct {
    struct _object *_ob_next;
    struct _object *_ob_prev;
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
    Py_ssize_t ob_size; /* Number of items in variable part */
} PyVarObject;

At this stage the structure definition consists of simple types or pointers to structures that are explicitly stated as struct the nice thing about which is that the compiler does not, at this stage, need to know what those structures are, since it knows that these are pointers to structures, it just needs to allocate the storage for an address to this structure and remember that the type to be allocated to them is required to match.

This is actually a case of forward references not circular dependency.

Code examined from CPython source at 2.7.11 version of Include/object.h simply because that is what I had to hand.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download