JNI基于C++的Java方法签名生成器

4 篇文章 0 订阅

背景

  1. 在C/C++调用Java时,需要写Java方法签名。
  2. 我写的有点累,还容易写错,错了还只能在运行时发现。

思路

  1. 我想在写签名的时候,按照Java方法的参数列表来写,方便检查。
  2. Java方法参数列表不同,所以我需要可变参数函数来实现组装Java方法签名。
  3. C/C++可变参数函数获取不到参数个数,我又懒得每次去数有几个参数,所以需要想办法计算参数个数。
    最终解决方法参考自:c/c++:计算可变参数宏 VA_ARGS 的参数个数

基于当前实现,有2个坑需要注意:

  1. 可变参数的个数最大为64。可以通过调整FL_ARG_COUNTFL_INTERNAL_ARG_COUNT_PRIVATE来拓展。
  2. 最终生成的签名字符串最大长度为8192,可以通过调整MAX_PRINT_SIZE来拓展。

源码

#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#include <iostream>
#include <sstream>
#include <string>

#define JNI_void_SIGN "V"
#define JNI_jboolean_SIGN "Z"
#define JNI_jbyte_SIGN "B"
#define JNI_jchar_SIGN "C"
#define JNI_jshort_SIGN "S"
#define JNI_jint_SIGN "I"
#define JNI_jlong_SIGN "J"
#define JNI_jfloat_SIGN "F"
#define JNI_jdouble_SIGN "D"
#define JNI_jstring_SIGN "Ljava/lang/String;"

// 用于计算参数个数
#define FL_ARG_COUNT(...)                                                     \
    FL_INTERNAL_ARG_COUNT_PRIVATE(                                            \
        0, ##__VA_ARGS__, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, \
        51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35,   \
        34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18,   \
        17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define FL_INTERNAL_ARG_COUNT_PRIVATE(                                         \
    _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, \
    _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, \
    _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, \
    _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, \
    _62, _63, _64, N, ...)                                                     \
    N

// 用于计算参数个数,然后传入GenJavaMethodSign()
#define GEN_JAVA_METHOD_SIGN(return_sign, ...) \
    GenJavaMethodSign(return_sign, FL_ARG_COUNT(__VA_ARGS__), ##__VA_ARGS__)

// 组装Java方法签名
std::string GenJavaMethodSign(const char* return_sign, int param_size, ...);

int main() {
    std::cout << GEN_JAVA_METHOD_SIGN(JNI_void_SIGN, JNI_jboolean_SIGN,
                                      JNI_jbyte_SIGN, JNI_jchar_SIGN)
              << std::endl;
    return 0;
}

/**
 * @brief 组装Java方法签名
 * @param
 *  return_sign 返回类型签名
 *  param_size 参数列表个数
 *  args 参数列表签名
 */
std::string GenJavaMethodSign(const char* return_sign, int param_size, ...) {
    // Note(guol)
    //  组装最终签名的格式字符串
    //  e.g. "(ZLjava/lang/String;)Ljava/lang/String;"
    std::stringstream ss;
    ss << '(';
    for (int i = 0; i < param_size; i++) {
        ss << "%s";
    }
    ss << ')' << return_sign;

    static const int MAX_PRINT_SIZE = 8192;
    const char* format = ss.str().c_str();
    char sign_buf[MAX_PRINT_SIZE];
    memset(sign_buf, 0, MAX_PRINT_SIZE);

    va_list __va;
    va_start(__va, param_size);
    int len = vsnprintf(sign_buf, MAX_PRINT_SIZE, format, __va);
    va_end(__va);

    if (len < 0) {
        // Todo(guol)
        assert(true);
    }

    // printf("[%04d] %s\n", len, sign_buf);
    return std::string(sign_buf, len);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值