我创建了一个简单的SO示例,演示了将va_list作为函数arg传递的各种方法。我试图解决的问题是将回调中的va_list从共享对象传递给主模块。
iou
以下是运行测试的结果...
/*libcode.vala shared library (libvala-0.38)*/
namespace SOTestLib {
public const string TESTSTR = "my test string";
public const string EXPECTFORMATSTR = "expect test:%s";
public const string EXPECTFORMATSTR_VA_ARG0 = "1==1";
public delegate bool delegatefnExpect (bool expression, string format, va_list valist);
public delegatefnExpect delfnExpect;
public delegate bool delegatefnString (string mystring);
public delegatefnString delfnString;
public string gTestStr;
public string gExpectResultStr;
private void show_string(string mystring) {
stdout.printf("show_string mystring[%s] gTestStr[%s]\n", mystring, gTestStr);
assert (mystring == gTestStr);
assert (delfnString != null);
delfnString(mystring);
}
private bool expect(bool expression, string sformat, ...) {
assert (delfnExpect != null);
assert (sformat == EXPECTFORMATSTR);
va_list _valist = va_list ();
gExpectResultStr = sformat.vprintf (_valist);
stdout.printf("expect[%s]\n", gExpectResultStr);
return delfnExpect(expression, sformat , _valist);
}
private void my_printf (string format, ...) {
va_list va_list = va_list ();
string res = format.vprintf (va_list);
stdout.puts (res);
}
public int run_demo() {
//REFER:https://valadoc.org/glib-2.0/string.vprintf.html
// Output: ``Shut up, K-9!``
my_printf ("Shut %s, %c-%d!\n", "up", 'K', 9);
gTestStr = TESTSTR;
show_string(TESTSTR);
expect(1 == 1, EXPECTFORMATSTR, EXPECTFORMATSTR_VA_ARG0);
return 0;
}
}
/*main.vala linked with libcode.so shared library (libvala-0.38)*/
using SOTestLib;
public bool cbfnString(string test_str) {
stdout.printf("cbfnString test_str[%s] gTestStr[%s]\n", test_str, gTestStr);
assert (test_str == gTestStr);
return true;
}
public bool cbfnExpect(bool expression, string format, va_list args) {
stdout.printf("cbfnExpect format[%s] format.length[%d]\n",
format, format.length);
assert (format == EXPECTFORMATSTR);
string res = format.vprintf(args);
assert (res != null);
stdout.printf("cbfnExpect res[%s] gExpectResultStr[%s]\n", res, gExpectResultStr);
assert(res == gExpectResultStr);
return expression;
}
static int main(string[] args) {
delfnString = (delegatefnString)cbfnString;
delfnExpect = (delegatefnExpect)cbfnExpect;
return run_demo();
}
由于某些原因,在cbfnExpect中,va_list args不再有效。似乎va_list地址(或结构中的地址)仅在共享库中有效。这不是va_list的正确/允许使用吗?
答案 0 :(得分:0)
在private bool expect
中,如果我注释掉gExpectResultStr
设置如下:
//gExpectResultStr = sformat.vprintf (_valist);
然后,在static int main
方法的第一行,我添加了:
gExpectResultStr = "expect test:1==1";
测试通过。由于gExpectResultStr
每次运行程序时都相同,所以我只是在程序启动时将其静态设置为正确的值。 删除 vprintf
中对expect
的来电似乎是修复它的原因。
我的猜测是,在C实现中调用va_list上的sformat.vprintf
会使va_list
无效。
当为生成和失败的代码分别生成的C代码时,这就是我想出的。盯着代码一段时间,可能搞乱va_list的唯一潜在部分是对g_strdup_vprintf()
的调用。我想这个函数释放了va_list?
$ diff -Naur libcode-pass.c libcode-fails.c
--- libcode-pass.c 2018-01-20 09:19:24.455838766 -0800
+++ libcode-fails.c 2018-01-20 09:19:59.631260461 -0800
@@ -66,26 +66,32 @@
SOTestLibdelegatefnExpect _tmp0_;
const gchar* _tmp1_;
va_list _valist = {0};
- FILE* _tmp2_;
- const gchar* _tmp3_;
- SOTestLibdelegatefnExpect _tmp4_;
- gboolean _tmp5_;
- const gchar* _tmp6_;
+ const gchar* _tmp2_;
+ gchar* _tmp3_;
+ FILE* _tmp4_;
+ const gchar* _tmp5_;
+ SOTestLibdelegatefnExpect _tmp6_;
gboolean _tmp7_;
+ const gchar* _tmp8_;
+ gboolean _tmp9_;
g_return_val_if_fail (sformat != NULL, FALSE);
_tmp0_ = so_test_lib_delfnExpect;
_vala_assert (_tmp0_ != NULL, "delfnExpect != null");
_tmp1_ = sformat;
_vala_assert (g_strcmp0 (_tmp1_, SO_TEST_LIB_EXPECTFORMATSTR) == 0, "sformat == EXPECTFORMATSTR");
va_start (_valist, sformat);
- _tmp2_ = stdout;
- _tmp3_ = so_test_lib_gExpectResultStr;
- fprintf (_tmp2_, "expect[%s]\n", _tmp3_);
- _tmp4_ = so_test_lib_delfnExpect;
- _tmp5_ = expression;
- _tmp6_ = sformat;
- _tmp7_ = _tmp4_ (_tmp5_, _tmp6_, _valist);
- result = _tmp7_;
+ _tmp2_ = sformat;
+ _tmp3_ = g_strdup_vprintf (_tmp2_, _valist);
+ _g_free0 (so_test_lib_gExpectResultStr);
+ so_test_lib_gExpectResultStr = _tmp3_;
+ _tmp4_ = stdout;
+ _tmp5_ = so_test_lib_gExpectResultStr;
+ fprintf (_tmp4_, "expect[%s]\n", _tmp5_);
+ _tmp6_ = so_test_lib_delfnExpect;
+ _tmp7_ = expression;
+ _tmp8_ = sformat;
+ _tmp9_ = _tmp6_ (_tmp7_, _tmp8_, _valist);
+ result = _tmp9_;
va_end (_valist);
return result;
}