C言語難しい
意外と反響があったので期待通りに動くようになったバージョンを掲載しておきます。
#include "Python.h" #include <stdio.h> int main(){ Py_Initialize(); unsigned long buf[10]; PyObject* i = Py_BuildValue("i", 0x1234567); printf("i: %p\n", i); memcpy(buf, i, sizeof(long) * 3); printf(" %016lx\n", buf[0]); /* refcount */ printf(" %016lx\n", buf[1]); /* type */ printf(" %016lx\n", buf[2]); /* value */ PyObject* cls = PyObject_GetAttrString(i, "__class__"); printf("i.__class__: %p\n", cls); /* type */ PyObject* x = Py_BuildValue("f", (float)0x123456 / (float)0x100000); printf("x: %p\n", x); memcpy(buf, x, sizeof(long) * 3); printf(" %016lx\n", buf[0]); /* refcount */ printf(" %016lx\n", buf[1]); /* type */ printf(" %016lx\n", buf[2]); /* value */ cls = PyObject_GetAttrString(x, "__class__"); printf("x.__class__: %p\n", cls); /* type */ Py_Finalize(); return 0; }
出力
i: 0x10101c590 0000000000000001 0000000100e7f180 0000000001234567 i.__class__: 0x100e7f180 x: 0x10100c240 0000000000000001 0000000100e7d690 3ff2345600000000 x.__class__: 0x100e7d690
(以下試行錯誤の過程)
期待通りに動かないコード
#include "Python.h" #include <stdio.h> int main(){ Py_Initialize(); PyObject* i = Py_BuildValue("i", 0xDEADBEEF); printf("i: %016x\n", i); printf("%016x: %032x\n", i, *(unsigned long*)i); /* refcount */ printf("%016x: %032x\n", i + 1, *(unsigned long*)(i + 1)); /* type */ printf("%016x: %032x\n", i + 2, *(unsigned long*)(i + 2)); /* value */ PyObject* cls = PyObject_GetAttrString(i, "__class__"); printf("cls: %016x\n", cls); /* type */ Py_Finalize(); return 0; }
(gdb) n 7 printf("i: %016x\n", i); (gdb) n i: 000000000021c580 8 printf("%016x: %032x\n", i, *(unsigned long long*)i); /* refcount */ (gdb) n 000000000021c580: 00000000000000000000000000000001 9 printf("%016x: %032x\n", i + 1, *(unsigned long long*)(i + 1)); /* type */ (gdb) n 000000000021c590: 000000000000000000000000deadbeef 10 printf("%016x: %032x\n", i + 2, *(unsigned long long*)(i + 2)); /* value */ (gdb) n 000000000021c5a0: 0000000000000000000000000012f180 12 PyObject* cls = PyObject_GetAttrString(i, "__class__"); (gdb) n 13 printf("cls: %016x\n", cls); /* type */ (gdb) n cls: 000000000012f180 16 Py_Finalize(); (gdb) print i $1 = (PyObject *) 0x10021c580 (gdb) print x No symbol "x" in current context. (gdb) print cls $2 = (PyObject *) 0x10012f180 (gdb) x/xg i 0x10021c580: 0x0000000000000001 (gdb) x 0x10021c588: 0x000000010012f180 ←ちゃんとclsを指してる (gdb) x 0x10021c590: 0xffffffffdeadbeef
うーん、%xが下8文字しか表示してないってこと?
全部%pに変えたらとりあえず8文字を超える部分も出るようになったが
i: 0x10b71c590 0x10b71c590: 0x1 0x10b71c5a0: 0xffffffffdeadbeef 0x10b71c5b0: 0x10b71c530 cls: 0x10b5d4180
えーと。それでも本当は2番めに表示されるものがclsと同じになってほしいのだが。
(gdb) print sizeof(Py_ssize_t) $1 = 8 (gdb) print sizeof(double) $2 = 8 (gdb) print sizeof(void*) $3 = 8 (gdb) print sizeof(long) $4 = 8 (gdb) print sizeof(long long) $5 = 8 (gdb) print sizeof(char) $6 = 1
memcpyしてみる
int main(){ Py_Initialize(); unsigned long buf[10]; PyObject* i = Py_BuildValue("i", 0xDEADBEEF); printf("i: %p\n", i); memcpy(buf, i, sizeof(i) * 3); printf("%p: %p\n", i, buf[0]); /* refcount */ printf("%p: %p\n", i + 1, buf[1]); /* type */ printf("%p: %p\n", i + 2, buf[2]); /* value */ PyObject* cls = PyObject_GetAttrString(i, "__class__"); printf("cls: %p\n", cls); /* type */ //PyObject* x = Py_BuildValue("f", 0xCAFEBABE + 0x100000000 + 0.0); Py_Finalize(); return 0; }
おお、できた。
i: 0x10811c590 0x10811c590: 0x1 0x10811c5a0: 0x10800c180 0x10811c5b0: 0xffffffffdeadbeef cls: 0x10800c180
本当は0でパディングしたいんだけど%pにはパディングを指定できないし、%xにすると4バイトしか出ないし。あ、そうか%lxか。
%016lxにしたら期待通りの出力になった。
C言語難しい。
あ、全部終わってからいまわかった。
(gdb) print sizeof(PyObject) $2 = 16
これが原因だな、そりゃそうだ。
以下メモ
typedef struct { PyObject_HEAD long ob_ival; } PyIntObject;
/* PyObject_HEAD defines the initial segment of every PyObject. */ #define PyObject_HEAD \ _PyObject_HEAD_EXTRA \ Py_ssize_t ob_refcnt; \ struct _typeobject *ob_type;
typedef struct { PyObject_HEAD double ob_fval; } PyFloatObject;