1 概述

(1)项目开发过程可能涉及多种语言,而多种语言之间如何数据交换格式是多种多样的,比如说:Java和JavaScript可以用json,Java和C#可以用xml等等。

(2)这里提供一种C与Java数据交换格式:struct <-> byte[] <-> javaBean

  • C不是一门面向对象的语言,但是C有结构体(struct),C一般操作结构体。
  • Java是一门面向对象的语言,所以Java一般操作对象。
  • 选择byte数组作为传输格式,节省通信成本,没有多余内容,不过极度依赖接收方与发送方之间的配合,毕竟如果字段错乱,将导致解析失败。

2 C语言:struct -> byte[]

#include <stdio.h>
#include <stdlib.h>
#include <mem.h> struct SS {
int f;
int d;
short g;
}; //结构定义 int main() {
unsigned char *b; // byte 指针
int N, i;
struct SS s = {7, 8, 4}; //声明一个结构对象并初始化
N = sizeof(struct SS); //结构大小
b = (unsigned char *) malloc(N); //动态分配b
memcpy(b, &s, sizeof(struct SS)); //内容复制
printf("%d", N);
for (int i = 0; i < N; i++) {
if (i > 0)
printf(",");
printf("%d", b[i]);
}
return 0;
}

3 Java语言:byte[] -> JavaBean

(1)方法1:依赖Unsafe类的数组操作接口

public class BytesToBean {
static class SS {
private int f;
private int d;
private short g;
// 省略getter和setter 构造方法 toString方法
} private static Unsafe unsafe; static {
try {
Field f = f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
unsafe = (Unsafe) f.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
} public static void main(String[] args){
//struct SS {
// int f;
// int d;
// short g;
//}; //结构体定义
byte[] bs = new byte[]{4, 0, 0, 0, 7, 0, 0, 0, 8, 0};
int offset = 0;
SS ss = new SS();
Field[] declaredFields = SS.class.getDeclaredFields();
for (Field declaredField : declaredFields) {
Class<?> clazz = declaredField.getType();
switch (clazz.getTypeName()) {
case "int":
int intValue = unsafe.getInt(bs, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset);
unsafe.putInt(ss, unsafe.objectFieldOffset(declaredField), intValue);
break;
case "short":
short shortValue = unsafe.getShort(bs, Unsafe.ARRAY_BYTE_BASE_OFFSET + offset);
unsafe.putShort(ss, unsafe.objectFieldOffset(declaredField), shortValue);
break;
}
offset += getFiledLength(clazz);
}
System.out.println(ss); // SS{f=4, d=7, g=8}
} private static int getFiledLength(Class clazz){
Object o = Array.newInstance(clazz, 0);
return unsafe.arrayIndexScale(o.getClass());
} }

(2)方法2:依赖ByteBuffer类的接口

public class BytesToBeans {
static class SS {
private int f;
private int d;
private short g;
// 省略getter和setter 构造方法 toString方法
} private static Unsafe unsafe; static {
try {
Field f = f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
unsafe = (Unsafe) f.get(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
byte[] bs = new byte[]{4, 0, 0, 0, 7, 0, 0, 0, 8, 0};
ByteBuffer byteBuffer = ByteBuffer.wrap(bs);
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
SS ss = new SS();
Field[] declaredFields = UnsafeTest.SS.class.getDeclaredFields();
for (Field declaredField : declaredFields) {
Class<?> clazz = declaredField.getType();
switch (clazz.getTypeName()) {
case "int":
int intValue = byteBuffer.getInt();
// unsafe.objectFieldOffset(declaredField) 获取该字段的偏移量
// Java对象:对象头 常量池数组 字段 方法
// 请参考:https://www.cnblogs.com/linzhanfly/p/9552910.html
unsafe.putInt(ss, unsafe.objectFieldOffset(declaredField), intValue);
break;
case "short":
short shortValue = byteBuffer.getShort();
unsafe.putShort(ss, unsafe.objectFieldOffset(declaredField), shortValue);
break;
}
}
System.out.println(ss); // SS{f=4, d=7, g=8}
}
}

4 总结

  • C与Java传输格式为byte数组,总体流程:struct <-> byte[] <-> javaBean。
  • C不熟悉
  • Java依赖Unsafe的对象字段赋值操作API、反射机制和ByteBuffer的byte数组操作API

最后,这也许不是最好的方案,我也不知道是否有更优秀的方案......

C结构体与JavaBean转化的更多相关文章

  1. C#结构体数组间的转化

    转自:http://developer.51cto.com/art/200908/143779.htm 解决C#结构体数组间的转化问题的由来:在写C#TCP通信程序时,发送数据时,如果是和VC6.0等 ...

  2. c#中关于结构体和字节数组转化

    最近在使用结构体与字节数组转化来实现socket间数据传输.现在开始整理一下.对于Marshal可以查阅msdn,关于字节数组与结构体转代码如下: using System; using System ...

  3. C++/C#结构体转化-二维数组-bytes To Strings

    C++结构体 typedef struct VidyoClientRequestGetWindowsAndDesktops_ { /*! The number of application windo ...

  4. 字节转化为结构体BytesToStruct

    //结构体转字节数组 public byte[] StructToBytes (object structObj) { int size = Marshal.SizeOf (structObj);// ...

  5. C#基础回顾(二)—页面值传递、重载与重写、类与结构体、装箱与拆箱

    一.前言 -孤独的路上有梦想作伴,乘风破浪- 二.页面值传递 (1)C#各页面之间可以进行数据的交换和传递,页面之间可根据获取的数据,进行各自的操作(跳转.计算等操作).为了实现多种方式的数据传递,C ...

  6. HDOJ 1009. Fat Mouse' Trade 贪心 结构体排序

    FatMouse' Trade Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  7. swift 的枚举、结构体、类

    一.Swift的枚举 枚举是一系相关联的值定义的一个公共的组类型,同时能够让你在编程的时候在类型安全的情况下去使用这些值.Swift中的枚举比OC中的枚举强大得多, 因为Swift中的枚举是一等类型, ...

  8. C#调用C/C++动态库 封送结构体,结构体数组

    一. 结构体的传递 #define JNAAPI extern "C" __declspec(dllexport) // C方式导出函数 typedef struct { int ...

  9. c# 利用结构体获取json数据

    最近做微信支付,要获取用户的openid,调用接口后返回的是json格式的数据,我想在c#后台把数据逐一取出,网上查了查,找到以下方法: 1.首先调用接口,要有一个post数据到指定url并返回数据的 ...

随机推荐

  1. asyncio之异步上下文管理器

    异步上下文管理器 前面文章我们提到了上下文管理器,但是这个上下文管理器只适用于同步代码,不能用于异步代码(async def形式),不过不用担心今天我们就来讨论在异步中如何使用上下文管理器. 特别提醒 ...

  2. 黑马vue---40、结合Node手写JSONP服务器剖析JSONP原理

    黑马vue---40.结合Node手写JSONP服务器剖析JSONP原理 一.总结 一句话总结: 服务端可以返回js代码给script标签,那么标签会执行它,并且可带json字符串作为参数,这样就成功 ...

  3. <JavaScript>可枚举属性与不可枚举属性

    在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的.可枚举性决定了这个属性能否被for…in查找遍历到. 一.怎么判断属性是否可枚举 js中基本包 ...

  4. 免费下载 SetupVPN CRX 3.7.0 for Chrome OR QQ浏览器

    免费下载 SetupVPN CRX 3.7.0 for Chrome OR QQ浏览器 Lifetime Free VPN(微劈嗯) 下载setupvpn 3.7.0的crx文件, 打开chrome的 ...

  5. tensorflow查看ckpt各节点名称

    from tensorflow.python import pywrap_tensorflowimport os checkpoint_path=os.path.join('output/res101 ...

  6. wangEditor编辑器控件里textarea的id不要用content

    头引用 <script type="text/javascript" src="js/jquery-1.10.2.min.js"></scri ...

  7. vim 全局替换

    :%s/foo/bar/g 把全部foo替换为bar,全局替换

  8. jQuery.fn.extend与jQuery.extend的区别

    jquery 本身并不提供 jQuery.color() 这个方法,如果我们需要对jQuery本身提供的方法进行扩展,则我们就需要是用jQuery.fn.extend: jQuery.fn.exten ...

  9. 通过命令行方式连接redis

    1.首先安装redis客户端 yum install redis 2.连接 redis-cli -h host -p port -a password host:远程redis服务器host port ...

  10. java 中 this 和 super 说明及在构造器中super()和this()相互调用执行顺序

    this this 表示当前对象 使用上细分的话,this有 this. 和this()的使用情况 ,下面我们开始细撸 this . 使用场景一: 在成员方法中,this.变量名 指带当前对象的变量, ...