C#自定义ShortBuffer实现异常,请求排查问题原因
移植Java.nio ShortBuffer到C#时的容量、位置及写入异常问题
我正在将Android库中的Java FSKModem代码移植到C#,由于C#没有Java.nio的ByteBuffer和ShortBuffer,自行实现了这两个类。其中ByteBuffer测试运行正常,但ShortBuffer出现以下异常:
- 容量(Capacity)显示为6,预期应为3(对应3个short类型元素)
- 初始位置(Position)为3而非0
HasRemaining()、Remaining()方法的计算逻辑不符合预期- 指定索引的
Put()方法无法正确写入数据
测试代码与输出
Java测试代码
import java.nio.ShortBuffer; public class ShortBufferTest { public static void main(String[] args) { ShortBuffer buffer = ShortBuffer.allocate(3); System.out.println("Capacity: " + buffer.capacity()); System.out.println("Position: " + buffer.position()); System.out.println("HasRemaining: " + buffer.hasRemaining()); System.out.println("Remaining: " + buffer.remaining()); buffer.put(0, (short)100); buffer.put(1, (short)200); buffer.put(2, (short)300); buffer.flip(); while(buffer.hasRemaining()) { System.out.println("Element: " + buffer.get()); } } }
Java输出
Capacity: 3 Position: 0 HasRemaining: true Remaining: 3 Element: 100 Element: 200 Element: 300
C#测试代码(自行实现的ShortBuffer)
public class ShortBufferTest { public static void Main() { var buffer = new ShortBuffer(new byte[6]); Console.WriteLine($"Capacity: {buffer.Capacity}"); Console.WriteLine($"Position: {buffer.Position}"); Console.WriteLine($"HasRemaining: {buffer.HasRemaining()}"); Console.WriteLine($"Remaining: {buffer.Remaining()}"); buffer.Put(0, (short)100); buffer.Put(1, (short)200); buffer.Put(2, (short)300); buffer.Flip(); while(buffer.HasRemaining()) { Console.WriteLine($"Element: {buffer.Get()}"); } } }
C#异常输出
Capacity: 6 Position: 3 HasRemaining: false Remaining: 0 Element: 0 Element: 0 Element: 0
问题排查与修正方向
1. 容量计算错误
Java的ShortBuffer容量是short元素的个数,而C#如果用byte[]作为底层存储,容量应等于byte数组长度 / 2。如果你的实现直接将byte数组长度作为ShortBuffer的Capacity,就会出现6(对应6字节=3个short)的错误值。
2. 初始Position与Limit设置错误
Java中ShortBuffer默认初始Position为0,Limit等于Capacity。检查C#实现的构造函数,是否错误地将Position设为byte数组长度/2,或者Limit未正确绑定到short元素个数。
3. Remaining/HasRemaining逻辑错误
Java中Remaining() = Limit - Position,HasRemaining()判断Remaining() > 0。如果你的C#实现中Limit使用了byte数组长度而非short元素个数,会导致计算逻辑完全错误。
4. 指定索引Put方法的字节偏移与端序问题
Java的Put(int index, short value)直接操作对应索引的short位置,而C#底层用byte数组时:
- 需计算正确的字节偏移量:
index * 2 - 注意端序匹配:Java ByteBuffer默认是大端序,而C#
BitConverter默认是小端序,需要手动反转字节确保一致性
修正后的ShortBuffer核心实现示例
public class ShortBuffer { private readonly byte[] _underlyingBytes; private int _position; private int _limit; private readonly bool _isBigEndian; public int Capacity => _underlyingBytes.Length / 2; public int Position { get => _position; set { if (value < 0 || value > _limit) throw new ArgumentOutOfRangeException(nameof(value)); _position = value; } } public int Limit { get => _limit; set { if (value < 0 || value > Capacity) throw new ArgumentOutOfRangeException(nameof(value)); _limit = value; if (_position > _limit) _position = _limit; } } public ShortBuffer(byte[] underlyingBytes, bool isBigEndian = true) { if (underlyingBytes.Length % 2 != 0) throw new ArgumentException("底层字节数组长度必须为偶数"); _underlyingBytes = underlyingBytes; _isBigEndian = isBigEndian; _position = 0; _limit = Capacity; } public int Remaining() => _limit - _position; public bool HasRemaining() => Remaining() > 0; public void Put(int index, short value) { if (index < 0 || index >= Capacity) throw new ArgumentOutOfRangeException(nameof(index)); int byteOffset = index * 2; byte[] shortBytes = BitConverter.GetBytes(value); // 匹配Java大端序 if (BitConverter.IsLittleEndian != _isBigEndian) Array.Reverse(shortBytes); _underlyingBytes[byteOffset] = shortBytes[0]; _underlyingBytes[byteOffset + 1] = shortBytes[1]; } public short Get() { if (!HasRemaining()) throw new InvalidOperationException("无剩余元素"); int byteOffset = _position * 2; byte[] shortBytes = new byte[2]; shortBytes[0] = _underlyingBytes[byteOffset]; shortBytes[1] = _underlyingBytes[byteOffset + 1]; if (BitConverter.IsLittleEndian != _isBigEndian) Array.Reverse(shortBytes); _position++; return BitConverter.ToInt16(shortBytes, 0); } public void Flip() { _limit = _position; _position = 0; } }
内容的提问来源于stack exchange,提问作者LimetaPeta
相关产品推荐
相关产品推荐

