将va_list作为函数参数传递

时间:2017-08-15 00:50:16

标签: vala

我创建了一个简单的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的正确/允许使用吗?

1 个答案:

答案 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;
 }