英文:
How to make pointer like object to the middle of an array
问题
我有一个字节缓冲区,并希望有一个指向第一个元素的标识符,该标识符应该指向不一定是数组本身的第一个元素。
我想要执行以下操作,但显然不起作用。是否有可能在不让函数uint32ToBuffer
知道它应该写入数组的初始位置的情况下执行此操作,以复制类似于C
语言的指针算术逻辑?
英文:
I have a byte buffer and would like to have identifier that points to the first element, which shall be written that does not necessary have to be the first element of the array itself.
private void uint32ToBuffer(int val, byte[] buffer)
{
buffer[0] = (byte)val;
buffer[1] = (byte)(val >>> 8);
buffer[2] = (byte)(val >>> 16);
buffer[3] = (byte)(val >>> 24);
}
I would like to do
byte[] buffer = new byte[512];
uint32ToBuffer(3, &buffer[2]);
but apparently it does not work. Is it somehow possible to do this without letting the function uint32ToBuffer
know the initial position from which it is supposed to write to the array to replicate pointer arithmetic logic from C
like languages?
答案1
得分: 0
以下是翻译好的部分:
- 使用
java.nio.buffer.ByteBuffer
ByteBuffer 是一个抽象概念,它们很像数组,因为它们是固定大小的,并表示字节。与 byte[]
不同,它具有有意义的 API,与 byte[]
不同,它内置了跟踪(也就是说,它有一个“位置”,而字节数组只有一个长度)。事实上,ByteBuffer 已经具有按小端格式写入整数到字节数组的功能!
byte[] buffer = new byte[512];
ByteBuffer bb = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN);
bb.position(2);
bb.putInt(3);
此时不再需要 uint32ToBuffer
方法;ByteBuffer 已经具备了这个功能。putInt(3)
调用:
-
将 3 作为 32 位整数写入位置
[2]
、[3]
、[4]
和[5]
处的字节(因为 bb 的位置为 2;这是相对写入)。具体来说,它写入了 3/0/0/0,因为缓冲区对象的字节顺序为LITTLE_ENDIAN
。默认情况下,它们是大端字节顺序,会写入 0/0/0/3。不确定为什么您需要小端字节顺序,这在当前已经非常过时,只有 x86/x64 芯片仍在使用它:互联网通常使用大端字节顺序,而在这个阶段更受欢迎的 ARM 芯片也是如此。如果您正在设计协议,我强烈建议您重新编写以使用大端字节顺序。 -
将 bb 的位置前进到 6。
还有一种绝对写入方法:
bb.putInt(2, 3);
这具有相同的效果(将 3
写入 buffer[2]
,并通过 buffer[3]
到 buffer[5]
写入 0
),但不依赖于缓冲区的位置值,也不会修改它。
我强烈建议您在这里以及在涉及“将小端整数写入字节数组”的所有其他操作中使用它。ByteBuffer API 可能已经包含您当前正在编写的实用方法的几乎所有内容。
- 只需传递位置
或者,只需传递位置;这在 Java API 中非常常见:
private void uint32ToBuffer(int val, byte[] buffer, int pos) {
buffer[pos] = (byte)val;
buffer[pos + 1] = (byte)(val >>> 8);
buffer[pos + 2] = (byte)(val >>> 16);
buffer[pos + 3] = (byte)(val >>> 24);
}
// ... 并且如果您愿意,为了方便起见:
private void uint32ToBuffer(int val, byte[] buffer) {
uint32ToBuffer(val, buffer, 0);
}
在 Java 中,无法创建其他数组的子切片;数组非常基本,几乎不支持可能被视为“高级”的任何功能。Java 也没有指针算术的任何形式,因此,创建一个引用,指向字节数组的第二个元素,这种情况是不可能的。在 C 语言中,字节数组本质上是“只是一个指针”,你不知道它的长度。在 Java 中,由于缓冲区溢出是一种相当常见的安全问题,这个概念在任何方面都__不存在__,这是故意的。字节数组确实是它们自己的数据结构,显然它们知道自己实际上是字节数组,也知道它们的长度。Java 使得不可能(除非编写一些修改的类文件,并禁用 JVM 的类验证器)编写缓冲区溢出问题。要做到这一点,指针__不能__以这种方式修改(在 Java 中无法“加 2”到指针上)。
希望这对您有所帮助!如果您需要更多翻译,请告诉我。
英文:
There is not.
You have a few options:
Use java.nio.buffer.ByteBuffer
ByteBuffer is an abstract concept; they are a lot like arrays in that they are fixed size and represent bytes. Unlike byte[]
, it has a meaningful API, and unlike byte[]
, it has baked in tracking (as in, it has a 'position', unlike byte arrays which only have a length). In fact, very awesome tracking, with marks, resets, and limits. In practice, a bytebuffers consist either of 'a light object wrapper around an array that contains the data' or 'direct access to a memory mapped I/O thing'.
In fact, ByteBuffer already has write-int-to-byte-array-as-little-endian functionality!
byte[] buffer = new byte[512];
ByteBuffer bb = ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN);
bb.position(2);
bb.putInt(3);
There is no further need for a uint32ToBuffer
method at this point; bytebuffer already has it. The putInt(3)
call:
- Writes '3' as 32-bit integer into the bytes at position
[2]
,[3]
,[4]
, and[5]
(because the bb's position was '2'; it's a relative write). Specifically, it writes 3/0/0/0 because the byte order of the buffer object isLITTLE_ENDIAN
. By default they are big endian and would have written 0/0/0/3. Not sure why you want little endian, that is a very outdated concept at this point, only x86/x64 chips still use it: The internet tends to be big endian, and ARM chips which are at this point quite a bit more popular are too. If you are designing the protocol I strongly advise you to rewrite things to be big endian instead. - Advances the position of the bb to 6.
There's also an absolute write:
bb.putInt(2, 3);
This has the same effect (writes 3
to buffer[2]
, and 0
to buffer[3]
through buffer[5]
), but doesn't depend on the buffer's position value nor modifies it.
I strongly recommend you use this here and for everything else you're doing that involves 'writing little-endian ints into a byte array'. The ByteBuffer API has probably just about everything you are currently writing utility methods for.
Just pass it along
Alternatively, pass along the position; this is very common in java APIs:
private void uint32ToBuffer(int val, byte[] buffer, int pos) {
buffer[pos] = (byte)val;
buffer[pos + 1] = (byte)(val >>> 8);
buffer[pos + 2] = (byte)(val >>> 16);
buffer[pos + 3] = (byte)(val >>> 24);
}
// ... and if you want, for convenience:
private void uint32ToBuffer(int val, byte[] buffer) {
uint32ToBuffer(val, buffer, 0);
}
There is no way in java to create arrays that are subslices of other arrays; array is extremely basic and supports absolutely nothing that could possibly count as 'fancy'. Java also has no pointer arithmetic of any sort, thus, making a reference that points 2 slots into a byte array just isn't a thing. In C land, a byte array is essentially 'just a pointer' and you have no idea how long it is. In java, because buffer overflows are a rather common security issue, that concept does not exist in any way and that is intentional. byte arrays really are their own data structure and notably know both that they are, in fact, a byte array, and how long they are. Java makes it impossible (unless you write some hacked class files and disable the JVM's class verifier) to program a buffer overrun issue. To do that, pointers cannot be modified in that fashion (you can't 'add 2' to a pointer in java).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论