You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何调用decipher后caldata值未变?及JS字节转Uint32方法

问题解答

一、调用decipher后caldata值未变化的原因及解决

原因

JavaScript中原始类型(Number、String等)采用按值传递。你的代码里caldata = new Uint32Array(u32)[0]取的是Uint32Array的第一个元素,属于Number类型(原始值)。调用decipher(caldata, key)时,传递的是这个原始值的副本,函数内部对参数v的操作不会影响外部的caldata。此外,函数中错误地将v当作数组访问v[0],但实际v是Number,v[0]结果为undefined,后续逻辑完全无效。

解决方法

传递引用类型(如数组、TypedArray实例),这类类型传递的是内存地址,函数内部修改会同步影响外部变量。

方案1:用数组包裹caldata

var ROUNDS = 64;
var DELTA = 0x9E3779B9;

var seed = new Uint8Array([0x15, 0x24, 0x86, 0xF0]);
var u32 = seed.buffer.slice(0);
// 用数组包裹原始值,传递引用
var caldata = [new Uint32Array(u32)[0]];
console.log("pre caldata!", caldata[0]);
var key = [0x12345678, 0x87654321, 0xAAAAAAAA, 0xBBBBBBBB];
decipher(caldata, key);

function decipher(v, k) {
  var y = v[0];
  var sum = (DELTA * ROUNDS) >>> 0;

  for (let i = 0; i < ROUNDS; i++) {
    y -= (((y << 4) >>> 0 ^ (y >>> 5)) + y) ^ (sum + k[(sum >>> 11) & 3]);
    sum = (sum - DELTA) >>> 0;
  }
  v[0] = y;
}

console.log("caldata!", caldata[0]); // 现在值会正常更新
console.log("Seed", seed);

方案2:直接操作Uint32Array实例(更贴合TypedArray场景)

var ROUNDS = 64;
var DELTA = 0x9E3779B9;

var seed = new Uint8Array([0x15, 0x24, 0x86, 0xF0]);
// 直接创建Uint32Array实例,本身就是引用类型
var caldataArr = new Uint32Array(seed.buffer.slice(0));
console.log("pre caldata!", caldataArr[0]);
var key = [0x12345678, 0x87654321, 0xAAAAAAAA, 0xBBBBBBBB];
decipher(caldataArr, key);

function decipher(v, k) {
  var y = v[0];
  var sum = (DELTA * ROUNDS) >>> 0;

  for (let i = 0; i < ROUNDS; i++) {
    y -= (((y << 4) >>> 0 ^ (y >>> 5)) + y) ^ (sum + k[(sum >>> 11) & 3]);
    sum = (sum - DELTA) >>> 0;
  }
  v[0] = y;
}

console.log("caldata!", caldataArr[0]); // 值已更新
console.log("Seed", seed);

二、字节数组转换为Uint32类型的实现

转换时需注意字节序(小端/大端),以下两种方式可按需选择:

方式1:直接用TypedArray转换(依赖主机字节序)

如果字节数组的字节序与主机系统一致,可直接用Uint32Array包裹Uint8Array的缓冲区:

var seed = new Uint8Array([0x15, 0x24, 0x86, 0xF0]);
// 转换结果的字节序由主机系统决定
var uint32Val = new Uint32Array(seed.buffer)[0];
console.log(uint32Val.toString(16)); // 小端主机输出f0862415,大端主机输出152486f0

方式2:用DataView指定字节序(精准可控)

若需要明确指定字节序(比如对应C语言的网络字节序——大端),使用DataView可以精准控制:

var seed = new Uint8Array([0x15, 0x24, 0x86, 0xF0]);
var dv = new DataView(seed.buffer);
// 第二个参数false表示大端字节序,true表示小端
var uint32BigEndian = dv.getUint32(0, false);
console.log(uint32BigEndian.toString(16)); // 固定输出152486f0

var uint32LittleEndian = dv.getUint32(0, true);
console.log(uint32LittleEndian.toString(16)); // 固定输出f0862415

内容的提问来源于stack exchange,提问作者JOSEPH129009

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 02:34:57