代码之家  ›  专栏  ›  技术社区  ›  my_question

如何创建bytearray类型的TCL变量

tcl
  •  0
  • my_question  · 技术社区  · 6 年前

    我正在使用TCL 8.4.20。

    所以我有以下代码:

    set a [binary format H2 1]
    set b [binary format H2 2]
    set c [binary format H2 3]
    set bytes $a
    append bytes $a
    append bytes $b
    append bytes $c
    
    puts $bytes
    

    我在Tcl的C源代码中的Tcl\u PutsObjCmd()函数处设置了一个断点,我看到它的参数$bytes是string类型,而我希望它是bytearray。

    问题1 :为什么?从第一次赋值到最后追加,“bytes”只接受二进制数据。

    我做这个实验的原因是,我们在C中有一个TCL扩展命令,它期望命令参数是字节数组类型的-它有一个检查值的typePtr应该是tclByteArrayType。我的TCL代码当前在此命令上失败,因为传递给该命令的数据是字符串类型,正如上面演示的那样。

    我在google上搜索了一下,似乎创建字节数组对象的“正确”方法是首先准备好每个字节,最后使用一个“二进制格式”命令将所有字节放在一个字节中。但这对我当前的TCL代码来说是一个相当大的改变。

    问题2 :如果我已经有一个TCL变量,其数据都是二进制文件(每个字节使用“二进制格式”创建,并使用“附加”组合),而其类型是字符串,那么如何通过一些TCL操作将其内部类型更改为“bytearray”?

    1 回复  |  直到 6 年前
        1
  •  0
  •   schlenk    6 年前

    从技术上讲,内部类型不是担保属性。一切都是一根弦。该代码可能会在任何时候让某个类型的字符闪烁起来。而依赖于内部类型的代码通常非常脆弱或彻底损坏。

    所以你的C代码应该调用 Tcl_GetByteArrayFromObj() 而不是偷看内部参数。如果对象还没有byteArray表示,则会进行适当的转换。

    关于您的问题:

    为什么不 append 是否保留字节数组类型?

    如果您做得正确并且从不触发字符串rep的创建,至少在8.6中是这样的。

    在tkcon中运行此功能 追加 将值转换为字符串:

    () 98 % set a [binary format H2 1]
    
    () 99 % set b [binary format H2 1]
    
    () 100 % ::tcl::unsupported::representation $a
    value is a bytearray with a refcount of 2, object pointer at 0000000005665420, internal representation 000000000587B280:0000000005665240, string representation ""
    () 101 % ::tcl::unsupported::representation $b
    value is a bytearray with a refcount of 2, object pointer at 000000000564EEB0, internal representation 000000000587B4A0:00000000056590E0, string representation ""
    () 102 % set x $a
    
    () 103 % ::tcl::unsupported::representation $x
    value is a bytearray with a refcount of 4, object pointer at 0000000005665420, internal representation 000000000587B280:0000000005665240, string representation ""
    () 104 % append x $b
    
    () 105 % ::tcl::unsupported::representation $x
    value is a string with a refcount of 3, object pointer at 0000000005663F50, internal representation 0000000005896BA0:000000000564F030, string representation ""
    

    之所以会发生这种情况,是因为bytearray创建了一个字符串rep(由于Tkcon回显了该值)。这个 追加 优化只适用于“pure”bytearray,例如没有字符串代表的bytearray。这类似于对“pure”列表的一些优化。

    因此,它是这样工作的,以防止闪烁的结果回波:

    () 106 % set b [binary format H2 1]; puts "pure"
    pure
    () 107 % set a [binary format H2 1]; puts "pure"
    pure
    () 108 % set x $a; puts "pure"
    pure
    () 109 % ::tcl::unsupported::representation $a
    value is a bytearray with a refcount of 3, object pointer at 0000000005658780, internal representation 000000000587B320:0000000005658CF0, no string representation
    () 110 % ::tcl::unsupported::representation $b
    value is a bytearray with a refcount of 2, object pointer at 000000000564ED60, internal representation 000000000587B500:0000000005658750, no string representation
    () 111 % ::tcl::unsupported::representation $x
    value is a bytearray with a refcount of 3, object pointer at 0000000005658780, internal representation 000000000587B320:0000000005658CF0, no string representation
    () 112 % append x $b; puts "pure"
    pure
    () 113 % ::tcl::unsupported::representation $x
    value is a bytearray with a refcount of 2, object pointer at 0000000005658690, internal representation 00000000058A5C60:0000000005658960, no string representation
    

    请注意 无字符串表示 部分

    如何将字符串转换为字节数组

    只需执行二进制格式:

    set x [binary format a* $x]