SWIG 将 C 指针字符串值转换为 TCL 字符串

SWIG convert C-Pointer stringvalue to tcl string

由于我对 C 和 SWIG 的了解有限,我无法采用任何 public 示例将 c 指针字符转换为 tcl 字符串.... 我总是遇到我的 tcl 变量没有被取消引用的问题 像这样:

tcl_str = _30e84c05ef550000_p_stringout2

string_pointer.c

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include "string_pointer.h"

stringout2  Itla_Get_Model_Version (int laser, char * mv_string)
   {
       stringout2 * pointer2;       
       char *mod_ver ="PPCL600";
       pointer2 = malloc( sizeof(stringout2) );
       pointer2-> modelvers= *mod_ver;
       printf ( "Itla_Get_Model_Version : read   %s   \n",  mod_ver );
       return  *pointer2 ;
   }   

string_pointer.h

#include <sys/types.h>
#include <sys/resource.h>


typedef struct {
      char      * modelvers;
} stringout2;

stringout2  Itla_Get_Model_Version   (int laser, char * mv_string) ;

string_pointer.swig

/* File : string_pointer.swig */
%module string_pointer

%{
#include "string_pointer.h"
%}

%include "typemaps.i"
%include "cpointer.i"
%include "cstring.i"

%typemap(argout) char* (char tmp) %{
     = &tmp;
%}

stringout2  Itla_Get_Model_Version    (int laser, char *OUTPUT) ;

%include "string_pointer.h"

test.tcl

load ./string_pointer.so

proc test { laser  } {

scan [Itla_Get_Model_Version $laser ] %s  a 
puts "$a "
return $a
}

set name [test 1 ]
puts "Itla_Get_Model_Version= $name"

当执行 tcl 脚本时,您得到:

Itla_Get_Model_Version : 读取 PPCL600
_f0a759f8d9550000_p_stringout2
Itla_Get_Model_Version= _f0a759f8d9550000_p_stringout2

所以我最终需要取消对指针的引用... 但是不知道怎么成功.....

C 函数已给定,无法修改!

有人知道怎么做吗?

如果您的字符串基本上是 ASCII 或 UTF-8,您需要做的就是告诉 SWIG 您的函数已经分配了正在 returning 的字符串。有关详细信息,请参阅 C 字符串上的 the SWIG docs

yourcode.c

char *Itla_Get_Model_Version (int laser, char * mv_string) {
    // I assume this is a proxy for something more complicated...
    const char *mod_ver ="PPCL600";
    size_t len = strlen(mod_ver) + 1;

    char *output = malloc(len);
    memcpy(output, mod_ver, len);
    printf ( "Itla_Get_Model_Version : read   %s   \n",  mod_ver );
    return output;
}

yourcode.h

char *Itla_Get_Model_Version(int laser, char * mv_string);

yourcode.swig

/* Tell SWIG that this function returns something to be freed */
%newobject Itla_Get_Model_Version

/* And now we can use the standard C header */
%include "yourcode.h"

如果上述简单的解决方案不起作用……

如果您对字符串使用不同的编码,或者如果您将它们包装在一个结构中(就像您在问题中所做的那样),事情会变得更加复杂。那就是你需要 typemap, particularly ones of the Tcl variety 的时候了。正确编写类型映射取决于理解您正在生成的值的语义 and/or 消耗 您正在使用的语言的语义。假设你想要包装,这里有一个非常简单的输出类型映射,可能工作:

%typemap(out) stringout2* {
    Tcl_SetObjResult(interp, Tcl_NewStringObj(->modelvers, -1));
    free();
}

您的函数还需要通过return pointer2;修改为return一个stringout2*,而不是stringout2因为否则你 在每次调用时泄漏内存。你可以return一个stringout2,但是如果你这样做那么你应该用[=19分配它=],而是将其作为结构直接保存在局部变量中。

在这种情况下,您要使用的类型映射是:

%typemap(out) stringout2 {
    Tcl_SetObjResult(interp, Tcl_NewStringObj(.modelvers, -1));
}

(注意类型不同,访问字段不同,缺少free。)
如果确实如此,您的结构应该声明为包含 const char *


如果您有不同编码的字符串(并且它不是 ISO 8859-1,您可以使用 Tcl_NewByteArrayObj 作弊并使用二进制字符串;这也是您想要分块的原因的二进制数据)然后你需要使用 Tcl_ExternalToUtfDString 编写一个类型映射,并且样板代码的数量会增加。 Tcl 坚持 它的内部字符串(几乎)是 UTF-8,ASCII 也可以,因为那是一个严格的子集;其他所有内容都必须转换。

如果这是您的需要,请再问一个问题。您可能正在处理 ASCII 或二进制数据,所以在请求之前我将单独进行编码转换(相当复杂!)。