如何在python 2.7中设置unicode字符串

时间:2018-03-25 06:49:36

标签: python python-2.7 unicode python-unicode unicode-string

我有一个unicode字符串f。我想将其memset为0. print f应该显示null(\ 0)

我正在使用ctypes.memset来实现这一目标 -

>     >>> f
>     u'abc'
>     >>> print ("%s" % type(f))
>     <type 'unicode'>
>     >>> import ctypes
>     **>>> ctypes.memset(id(f)+50,0,6)**
>     **4363962530
>     >>> f
>     u'abc'
>     >>> print f
>     abc**

为什么在unicode字符串的情况下内存位置没有得到memset? 它适用于str对象。

感谢您的帮助。

1 个答案:

答案 0 :(得分:4)

首先,这几乎肯定是一个非常糟糕的主意。 Python期望字符串是不可变的。有一个原因,即使C API也不允许您在标记为准备好之后更改其内容。如果你只是这样做来解释翻译的实现,那可能很有趣也很有启发性,但是如果你为了任何现实目的而做这件事,你很可能做错了。

特别是,如果您正在为安全性而做,那么您几乎肯定要做的就是不首先创建unicode,而是创建比方说,bytearray使用您的字符串的UTF-16或UTF-32编码,可以安全,便携,更轻松地将其清零。

无论如何,没有理由期望两个完全不同的类型应该将它们的缓冲区存储在相同的偏移量。

在CPython 2.x中,strPyStringObject

typedef struct {
    PyObject_VAR_HEAD
    long ob_shash;
    int ob_sstate;
    char ob_sval[1];
} PyStringObject;

ob_sval是缓冲区; 64位版本的偏移应该是36,而我认为32位版本的偏移应该是24。

在评论中,您说:

  

我在某处读到了它,而且我的系统中字符串类型的偏移量是37,这就是sys.getsizeof(&#39;&#39;)显示的 - &gt; &GT;&GT;&GT; sys.getsizeof(&#39;&#39;)37

字符串缓冲区的偏移量实际上是36,而不是37。而它甚至接近的事实只是str实现方式的巧合。 (希望你能通过查看struct定义来理解为什么 - 如果没有,你绝对不应该像这样编写代码。)没有理由期待在不查看其实现的情况下,为其他类型工作的相同技巧。

unicodePyUnicodeObject

typedef struct {
    PyObject_HEAD
    Py_ssize_t length;          /* Length of raw Unicode data in buffer */
    Py_UNICODE *str;            /* Raw Unicode buffer */
    long hash;                  /* Hash value; -1 if not set */
    PyObject *defenc;           /* (Default) Encoded version as Python
                                   string, or NULL; this is used for
                                   implementing the buffer protocol */
} PyUnicodeObject;

它的缓冲区甚至不在对象本身内; str成员是指向缓冲区的指针(不保证在结构之后)。它的偏移应该是64位构建上的24,并且(我认为)32位构建上的20。所以,为了做同等的事情,你需要在那里读指针,然后按照它来找到memset的位置。

如果您使用的是窄版本的Unicode,它应该如下所示:

>>> ctypes.POINTER(ctypes.c_uint16 * len(g)).from_address(id(g)+24).contents[:]
[97, 98, 99]

查找(uint16_t *)(((char *)g)+24)的ctypes翻译并阅读以*that开头并以*(that+len(g))结尾的数组,这是您必须要做的事情如果您正在编写C代码并且无法访问unicodeobject.h标题。

(在我刚刚引用的测试中,g位于0x10a598090,而其src指向0x10a3b09e0,因此缓冲区不是紧跟在结构之后,或者它附近的任何位置;它之前约2MB。)

对于广泛的Unicode构建,与c_uint32相同。

所以,这应该显示你想要的memset

你也应该看到你对'安全'的尝试有严重的影响。这里。 (如果我必须指出它,那又是你不应该写这段代码的另一个迹象。)