首页 > 解决方案 > SWIG 将 C 指针字符串值转换为 tcl 字符串

问题描述

由于我在 C 和 SWIG 方面的知识有限,我无法采用任何公共示例将 c 指针字符转换为 tcl 字符串....我总是陷入我的 tcl 变量没有被取消引用的问题这个 :

tcl_str = _30e84c05ef550000_p_stringout2

字符串指针.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 ;
   }   

字符串指针.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) %{
    $1 = &tmp;
%}

stringout2  Itla_Get_Model_Version    (int laser, char *OUTPUT) ;

%include "string_pointer.h"

测试.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-function 是给定的,不能修改!

有大佬知道怎么弄吗?

标签: ctclswigc-strings

解决方案


如果您的字符串基本上是 ASCII 或 UTF-8,您需要做的就是告诉 SWIG 您的函数已分配它返回的字符串。有关详细信息,请参阅关于 C 字符串的 SWIG 文档。

你的代码.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;
}

你的代码.h

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

你的代码.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"

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

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

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

您的函数还需要stringout2*修改为通过执行返回 a return pointer2;,而不是 a stringout2,否则您在每次调用时泄漏内存。您可以返回 a stringout2,但如果这样做,则不应将分配给malloc,而应将其作为结构直接保存在局部变量中。

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

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

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


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

问另一个问题,如果那是你需要的。您可能正在处理 ASCII 或二进制数据,因此在请求之前,我将单独保留(相当复杂一点!)编码转换。


推荐阅读