使用js-ctypes——处理数据

原文:
https://developer.mozilla.org/en/js-ctypes/Using_js-ctypes/Working_with_data

创建CData对象

使用js-ctypes的数据类型的由CType对象表示的。这些都是javascript构造函数。它们都是可调用的函数,你可以用来创建新的这种类型的CData对象。有几种方式进行创建新的CData对象。

创建CData对象不初始化

不立即指定初始值有三种形式的语法来创建CData对象。
var myCDataObj = new type;
var myCDataObj = new type();
var myCDataObj = type();
这些做了同样的事情:它们返回一个新的指定类型的CData对象,其数据缓存全部由0填充。
注:如果type.size是undefined,这种方式创建新对象将会抛出一个TypeError的异常。

创建CData对象并初始化

类似的,你可以用指定的值在类型创建的时候初始化CData对象,这可以通过调用CType的构造函数时指定它们为一个参数,像这样:
var myCDataObj = new type(value);
var myCDataObj = type(value);
如果指定类型的大小不是undefined,该指定的值将会转换为给定的类型。如果转换无法进行,将会抛出TypeError异常。结果会复制到一个新的CData对象中。如果初始值已经是一个CData对象,原来的对象就会简单的直接复制到新的中去。
如type是一个没指定长度的数组类型,将会执行下面的步骤:
如果value是一个大小值,则创建一个以该值为长度的数组,其每个单元已经可以接受相同的类型作为指定的数组。这与使用new ArrayType(type.elementType, value)是一样的。
如果type表示的是一个javascript字符串(也就是说,一个jschar数组,末尾跟着null),则创建该字符串的拷贝并返回。
如果type是一个8位字符数组并且value是一个UTF-16字符串,新的CData对象是将UTF-16字符串转换为UTF-8的结果,以null结尾。
如果value是一个javascript数组对象且长度非负,则创建一个新的数组并且value指定的数组内容转换为CData对象并复制到新的数组中,然后返回这个新的数组。
如果上述都不满足,则抛出TypeError异常。如果type是ctypes.void_t,抛出TypeError异常。

例:创建一个数组

let arrayType = ctypes.ArrayType(ctypes.int32_t);
let myArray = new arrayType(5);

这里,myArray.length是5;数组中有5个项。myArray.constructor.size是20.数组的数据缓存的总大小是20byte(5项,每项4byte)

类型转换

你可以通过使用ctypes.cast()函数将数据从一种类型转换为另一种类型:
var newObj = ctypes.cast(origObj, newType);
这会返回一个新的对象,其数据块与原始对象共享,但是其类型是newType。如果新类型的大小是undefined或者比原始对象的数据块大,则抛出TypeError异常。
这与标准C类型转换或者C++的reinterpret_cast非常相似。

数据与指针

一个CData对象表示了内存中一个C的值。你总是可以通过CData对象的address()方法获取一个指向这个C值的指针。

对象可以共享内存

牢记两个(或更多)CData对象可以共享同一片内存块作为它们的内容非常重要。例如,在类型转换的时候会发生。这叫做别名混淆(aliasing)。共享的内存可以是全部也可以是一部分。例如:
const Point = new ctypes.StructType("Point", [{x: ctypes.int32_t}, {y: ctypes.int32_t}]);
const Rect = new ctypes.StructType("Rect", [{topLeft: Point}, {bottomRight: Point}]);

var r = Rect();
var p = r.topLeft;
r.topLeft.x = 100;

这里,p是Rect对象r的一个指向topLeft的引用。设置p.x的值将会影响r.topLeft.x的值。

相等的怪现象Quirks in equality

Javascript中判断相等与否与C中有着很大的不同,详细说明见原文。

例:检查一个整型值

例如,在需要检查一个整型值是不是5的时候可以这样做:
var t = ctypes.int32_t(5);
if (t.toString() == "ctypes.int32_t(5)") {
// it's 5
}

处理字符串

C函数需要的字符串是字符数组,字符串的末尾由一个null字符标志。然而,在javascript中,使用String对象来表示字符串。

将C字符串转换为javascript的字符串

CData对提供了readString()方法来从指定的字符串读取字节并返回一个新的javascriptString对象表示那个字符串。
注意:源代码中的C字符串认为是UTF-8的,且认为其以null结尾。如果你需要转换不满足这个条件的字符串,则需要你自己来实现。
例如:var jsString = timeStr.readString();

将javascript字符串转换为C字符串

将javascript字符串转换为C格式的字符串非常简单,只需要创建一个包含这个javascript字符串的字符数组。
var myUTF8String = ctypes.char.array()("Original string.");
这创建一个UTF-8格式的null结尾的字符串在字符数组中,名为myUTF8String。
如果你需要一个UTF-16字符串,可以这样:
var myUTF16String = ctypes.jschar.array()("Original string.");
注意:这里,没有指定编码方式;你可以只检索UTF-8或UTF-16的字符串。

C函数中使用字符串

你在使用它们作为C函数的输入参数的时候甚至不需要进行字符串转换。它们自动为你进行了转换。只需要传递javascript的String对象。
但是,当C函数返回的时候,它们返回的是一个char.ptr或者jschar.ptr(也就是一个指向8位或16位字符数组)。你不得不自己对其进行转换,如上面所描述的那样。

处理指针

读取指针所引用的数据

这个例子创建一个指向整型数据的指针,然后使用PointerType对象的contents属性来获取指针指向的数据。
var i = ctypes.int32_t(9); // Create a C integer whose value is 9
var p = i.address(); // Create a pointer to the integer variable i
if (p.contents == 9) { // Look at the contents of the pointer
// the value is 9
} else {
// the value isn't 9
}

设置指针引用的数据

你也可以使用contents属性来设置指针指向的变量的值。
var i = ctypes.int32_t(9); // Create a C integer variable whose value is 9
var p = i.address(); // Get a pointer to i
p.contents = 12; // Change the value of i to 12

检查指针是否为空

这个例子说明了使用isNull()方法来确定一个指针是否为空。
var p = someCDataObject.address();

if (p.isNull()) {
// the pointer is null
} else {
// the pointer isn't null
}


检查两个指针是否相等

由于在javascript中检测相等的特殊,检查两个指针是否相等的最好方式是将它们转换成字符串,然后比较字符串。
if (i.address().toString() == ctypes.int32_t.ptr(5).toString()) {
// the integer i's address is 5
}

上面这个例子不仅仅比较了地址,还比较了类型,因此,如果i的地址是5并且i确实是ctypes.int32_t类型,上面的比较才成功。
if (ctypes.cast(p, ctypes.uintptr_t).value.toString() == "5") {
// the pointer p's address is 5
}

这里将指针转换为一个ctypes.uintptr_t类型,其value属性返回一个ctypes.UInt64的值。调用toString()返回十进制整数值。

使用指针数组

如果你需要处理C函数接收的是指针数组作为输入,你可以构造一个指针的数组,像这样:
var ptrArrayType = ctypes.char.ptr.array(5);
var myArray = ptrArrayType();
var someCFunction = library.declare("someCFunction", ctypes.default_abi, ctypes.void_t, ctypes.char.ptr.array());
someCFunction(myArray);

第一行声明了一个新的数组类型,可以容纳5个指向C字符数组的指针。这可能是一个字符串数组。接下来的一行实例化了一个该类型的对象,创建了一个新的数组。这个数组中每个指针都初始化为null。第三行声明了一个接受这个数组为输入参数的C函数。最后一行调用这个函数。

64-bit integers

略之,请参考原文。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章