当前位置: 首页 > 面试题库 >

如何使Swig正确包装在C中修改为Java Something-other-other的char *缓冲区?

章建木
2023-03-14
问题内容

我正在尝试包装一些用于Java的旧代码,很高兴看到Swig能够处理头文件,并且生成了一个几乎可以正常工作的出色包装器。现在,我正在寻找使它真正起作用的深层魔术。

CI中的功能看起来像这样

DLL_IMPORT int DustyVoodoo(char *buff, int len,  char *curse);

此函数返回的该整数是万一失败的错误代码。参数是

  • buff 是一个字符缓冲区
  • len 是缓冲区中数据的长度
  • curse 另一个字符缓冲区,其中包含调用DustyVoodoo的结果

因此,您可以看到行进方向,结果实际上是通过第三个参数返回的。这也len很令人困惑,因为这可能是两个缓冲区的长度,在调用代码中它们总是被分配为相同的大小,但是鉴于DustyVoodoo我不认为它们需要相同。为了安全起见,实际上两个缓冲区的大小应相同,例如512个字符。

为绑定生成的C代码如下:

SWIGEXPORT jint JNICALL Java_pemapiJNI_DustyVoodoo(JNIEnv *jenv, jclass jcls, jstring

jarg1, jint jarg2, jstring jarg3) {
  jint jresult = 0 ;
  char *arg1 = (char *) 0 ;
  int arg2 ;
  char *arg3 = (char *) 0 ;
  int result;

  (void)jenv;
  (void)jcls;
  arg1 = 0;
  if (jarg1) {
    arg1 = (char *)(*jenv)->GetStringUTFChars(jenv, jarg1, 0);
    if (!arg1) return 0;
  }
  arg2 = (int)jarg2; 
  arg3 = 0;
  if (jarg3) {
    arg3 = (char *)(*jenv)->GetStringUTFChars(jenv, jarg3, 0);
    if (!arg3) return 0;
  }
  result = (int)PemnEncrypt(arg1,arg2,arg3);
  jresult = (jint)result; 
  if (arg1) (*jenv)->ReleaseStringUTFChars(jenv, jarg1, (const char *)arg1);
  if (arg3) (*jenv)->ReleaseStringUTFChars(jenv, jarg3, (const char *)arg3);
  return jresult;
}

它所做的是正确的。但是,它错过了一个事实,即cursed它不仅是输入,而且会被函数更改并应作为输出返回。它还不知道Java字符串确实是缓冲区,应该由适当大小的数组作为后盾。

我认为Swig在这里可以做正确的事情,只是无法从文档中弄清楚如何告诉Swig它需要知道什么。房子里有字型图吗?


问题答案:

感谢托马斯的正确指导。解决方案是创建一个使用StringBuffer的自定义类型映射,以将结果返回。我examples/java/typemap在SWIG安装目录中找到了代码。在搜索之前,我一定忽略了这一点。

我已在下面附加了示例代码,目前正在使用建议的替代方法。但是,使用BYTE类型映射的第一种方法可能需要对Java代码进行一些更改,但从长远来看实际上可能更有意义。

感谢您的帮助,现在我可以看看我是否可以接受自己的答案…

/* File : example.i */
%module example
%{
/*
   example of a function that returns a value in the char * argument
   normally used like:

   char buf[bigenough];
   f1(buf);
*/

void f1(char *s) {
  if(s != NULL) {
    sprintf(s, "hello world");
  }
}

void f2(char *s) {
  f1(s);
}

void f3(char *s) {
  f1(s);
}

%}

/* default behaviour is that of input arg, Java cannot return a value in a 
 * string argument, so any changes made by f1(char*) will not be seen in the Java
 * string passed to the f1 function.
*/
void f1(char *s);

%include various.i

/* use the BYTE argout typemap to get around this. Changes in the string by 
 * f2 can be seen in Java. */
void f2(char *BYTE);



/* Alternative approach uses a StringBuffer typemap for argout */

/* Define the types to use in the generated JNI C code and Java code */
%typemap(jni) char *SBUF "jobject"
%typemap(jtype) char *SBUF "StringBuffer"
%typemap(jstype) char *SBUF "StringBuffer"

/* How to convert Java(JNI) type to requested C type */
%typemap(in) char *SBUF {

  $1 = NULL;
  if($input != NULL) {
    /* Get the String from the StringBuffer */
    jmethodID setLengthID;
    jclass sbufClass = (*jenv)->GetObjectClass(jenv, $input);
    jmethodID toStringID = (*jenv)->GetMethodID(jenv, sbufClass, "toString", "()Ljava/lang/String;");
    jstring js = (jstring) (*jenv)->CallObjectMethod(jenv, $input, toStringID);

    /* Convert the String to a C string */
    const char *pCharStr = (*jenv)->GetStringUTFChars(jenv, js, 0);

    /* Take a copy of the C string as the typemap is for a non const C string */
    jmethodID capacityID = (*jenv)->GetMethodID(jenv, sbufClass, "capacity", "()I");
    jint capacity = (*jenv)->CallIntMethod(jenv, $input, capacityID);
    $1 = (char *) malloc(capacity+1);
    strcpy($1, pCharStr);

    /* Release the UTF string we obtained with GetStringUTFChars */
    (*jenv)->ReleaseStringUTFChars(jenv,  js, pCharStr);

    /* Zero the original StringBuffer, so we can replace it with the result */
    setLengthID = (*jenv)->GetMethodID(jenv, sbufClass, "setLength", "(I)V");
    (*jenv)->CallVoidMethod(jenv, $input, setLengthID, (jint) 0);
  }
}

/* How to convert the C type to the Java(JNI) type */
%typemap(argout) char *SBUF {

  if($1 != NULL) {
    /* Append the result to the empty StringBuffer */
    jstring newString = (*jenv)->NewStringUTF(jenv, $1);
    jclass sbufClass = (*jenv)->GetObjectClass(jenv, $input);
    jmethodID appendStringID = (*jenv)->GetMethodID(jenv, sbufClass, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;");
    (*jenv)->CallObjectMethod(jenv, $input, appendStringID, newString);

    /* Clean up the string object, no longer needed */
    free($1);
    $1 = NULL;
  }  
}
/* Prevent the default freearg typemap from being used */
%typemap(freearg) char *SBUF ""

/* Convert the jstype to jtype typemap type */
%typemap(javain) char *SBUF "$javainput"

/* apply the new typemap to our function */
void f3(char *SBUF);


 类似资料:
  • 与另一个包围盒求并集,得到的也是一个包围盒。 参数 名称 类型 默认值 描述 other zrender.BoundingRect 另一个包围盒。 返回值 新的包围盒,类型:zrender.BoundingRect。

  • 判断两个包围盒是否相交。 参数 名称 类型 默认值 描述 other zrender.BoundingRect 另一个包围盒。 返回值 相交部分的包围盒,类型:zrender.BoundingRect。

  • 从另一个包围盒复制属性。 参数 名称 类型 默认值 描述 other zrender.BoundingRect 另一个包围盒。

  • To learn more about the Basic Elements To see the full API document in Markdown format, see APIs To contribute to Gio.js's code base, read Developer Guide

  • HTTP 303 See Other重定向状态响应代码(通常作为一个 PUT或POST操作的结果发回)表示重定向不链接到新上载的资源,而是链接到其他页面,如确认页面或上载进度页面。用于显示此重定向页面的方法始终是GET。 状态 303 See Other 规范 规范 标题 RFC 7231,第6.4.4节:303见其他 超文本传输协议(HTTP / 1.1):语义和内容 浏览器兼容性 Featur

  • 链接静态库优化 Other Linker Flags (OTHER_LDFLAGS)作用效果及作用时机探究 一、准备 文件目录结构 . ├── OCStaticLib │ ├── OCTest.h │ ├── OCTest.m │ ├── OCTest.o │ ├── build.sh │ ├── libOCTest │ └── libOCT