指向extern变量的静态初始化

时间:2014-09-15 05:52:37

标签: c portability linkage python-internals

我想了解Python导入系统的内部结构,包括粗糙的部分。在Python C API documentation中,对于这样一个粗糙的地方有简洁的引用:

  

这是非常重要的,我们将挑选它的顶部   更进一步:

PyObject_HEAD_INIT(NULL)
     

这条线有点疣;我们想要什么   写是:

PyObject_HEAD_INIT(&PyType_Type)
     

作为类型对象的类型   “类型”,但这并不严格符合C和一些编译器   抱怨。

为什么这不严格符合C?为什么有些编译器会在没有投诉的情况下接受这种情况而其他编译器却没有?

我现在认为以下内容具有误导性,请跳至"实质性编辑"

向下滚动页面我认为是一个线索。这句话关于初始化结构的另一个成员,但它听起来像是同一个问题,这一次被解释了。

  

我们想把它分配到tp_new插槽,但我们不能,因为   可移植性,在某些平台或编译器上,我们不能静态   使用另一个C中定义的函数初始化结构成员   模块

这仍然让我有点困惑,部分原因是"模块"的奇数词选择。我认为第二个引用意味着依赖于对单独编译单元中的函数的调用的静态初始化是非标准扩展。我仍然不明白为什么会如此。这是第一次引用的内容吗?

实质性编辑:

建议使用PyObject_HEAD_INIT(NULL)进入PyTypeObject实例初始化的最顶端。

PyTypeObject的定义如下所示:

typedef struct _typeobject {
    PyObject_VAR_HEAD
    const char *tp_name; /* For printing, in format "<module>.<name>" */
    Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */

    /* Methods to implement standard operations */

    destructor tp_dealloc;

/*... lots more ... */

} PyTypeObject;

PyObject_HEAD_INIT(NULL)宏用于初始化PyTypeObject实例的顶部。 PyTypeObject定义的顶部由宏PyObject_VAR_HEAD创建。 PyObject_VAR_HEAD是:

/* PyObject_VAR_HEAD defines the initial segment of all variable-size
 * container objects.  These end with a declaration of an array with 1
 * element, but enough space is malloc'ed so that the array actually
 * has room for ob_size elements.  Note that ob_size is an element count,
 * not necessarily a byte count.
 */
#define PyObject_VAR_HEAD               \
    PyObject_HEAD                       \
    Py_ssize_t ob_size; /* Number of items in variable part */
#define Py_INVALID_SIZE (Py_ssize_t)-1

反过来,PyObject_HEAD扩展为:

/* PyObject_HEAD defines the initial segment of every PyObject. */
#define PyObject_HEAD                   \
    _PyObject_HEAD_EXTRA                \
    Py_ssize_t ob_refcnt;               \
    struct _typeobject *ob_type;

_PyObject_HEAD_EXTRA仅用于调试版本,通常扩展为空。由PyObject_HEAD_INIT宏初始化的成员是ob_refcnt和ob_type。 ob_type是我们想要用&PyType_Type初始化的那个,但我们被告知会违反C标准。 ob_type指向_typeobject,它是作为PyTypeObject的typedef&(我们尝试初始化的结构)。我们使用PyObject_HEAD_INIT宏来初始化这两个值,扩展如下:

#define PyObject_HEAD_INIT(type)        \
    _PyObject_EXTRA_INIT                \
    1, type,

因此我们在1处开始引用计数并将成员指针设置为type参数中的任何内容。 Python文档说我们不能将类型参数设置为PyType_Type的地址,因为这不是严格的标准C,所以我们解决了NULL。

PyType_Type在同一个翻译单元中声明了几行。

PyAPI_DATA(PyTypeObject) PyType_Type; /* built-in 'type' */

PyAPI_DATA在别处定义。它有一些不同的条件定义。

#define PyAPI_DATA(RTYPE) extern __declspec(dllexport) RTYPE
#define PyAPI_DATA(RTYPE) extern RTYPE

因此,Python API文档说我们要使用指向先前声明的使用extern限定符声明的PyTypeObject的指针初始化PyTypeObject的实例。违反C标准的是什么?

PyType_Type的初始化发生在.c文件中。如上所述,初始化PyTypeObject的典型Python扩展将由使用此初始化编译的代码动态加载:

PyTypeObject PyType_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "type",                                     /* tp_name */
    sizeof(PyHeapTypeObject),                   /* tp_basicsize */
    sizeof(PyMemberDef),                        /* tp_itemsize */
    (destructor)type_dealloc,                   /* tp_dealloc */

/* ... lots more ... */
}

2 个答案:

答案 0 :(得分:1)

PyObject_HEAD_INIT(&PyType_Type)

可生产

1, &PyType_Type

初始化字段

Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;

PyType_Type由PyAPI_DATA(PyTypeObject) PyType_Type定义,产生

extern PyTypeObject PyType_Type;

可能带有__declspec限定符。 PyTypeObject是struct _typeobject的typedef,所以我们有

extern struct _typeobject PyType_Type;

所以PyObject_HEAD_INIT(&PyType_Type)会使用struct _typeobject* ob_type初始化struct _typeobject*字段...这肯定是有效的C,所以我不明白为什么他们说它不是。

答案 1 :(得分:0)

我在Python源代码的其他地方得到了解释。

/* We link this module statically for convenience.  If compiled as a shared
   library instead, some compilers don't allow addresses of Python objects
   defined in other libraries to be used in static initializers here.  The
   DEFERRED_ADDRESS macro is used to tag the slots where such addresses
   appear; the module init function must fill in the tagged slots at runtime.
   The argument is for documentation -- the macro ignores it.
*/
#define DEFERRED_ADDRESS(ADDR) 0

然后使用宏,其中NULL出现在OP的顶部。

PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)