[英]How can I translate C code that copies the length of an integer value followed by a byte string consisting of the value into arbitrary bytes?
I'm using this C code to encode several values into a byte string:我正在使用此 C 代码将几个值编码为一个字节字符串:
unsigned char *buf = malloc(10);
*(unsigned int *)buf = 6;
memcpy(buf + 4, source, 6);
// Repeat for more values...
It copies a uint32
with the length of the value followed by a byte string consisting of the value.它复制一个uint32
,其长度为值,后跟由该值组成的字节字符串。
How can this be done in Rust?如何在 Rust 中做到这一点? There doesn't seem to be a straightforward way (that I know of) to manipulate memory at arbitrary alignments and widths.似乎没有一种直接的方法(我知道)以任意对齐方式和宽度操作内存。
user4815162342's answer provides a direct translation. user4815162342 的回答提供了直接翻译。 Here is a more idiomatic Rust approach:这是一个更惯用的 Rust 方法:
use byteorder::{BigEndian, WriteBytesExt}; // 1.3.4
use std::io::Write;
fn main() {
let source = [0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let mut buff = Vec::with_capacity(10);
buff.write_i32::<BigEndian>(6).unwrap();
buff.write(&source).unwrap();
}
This works because the Write
trait is implemented for Vec<u8>
.这是有效的,因为Write
trait 是为Vec<u8>
。
Using the byteorder
crate allows you to specify the endianness you want the length to be written with.使用byteorder
crate 允许您指定要写入长度的字节序。
There are some differences to the C version:与 C 版本有一些区别:
write
would expand the size of the buffer as needed (although it will be more efficient if you create it with the needed size to begin with) write
会根据需要扩展缓冲区的大小(尽管如果您以所需的大小开始创建它会更有效)
write
returns a Result
indicating if there was an error. write
返回一个Result
指示是否有错误。 In this sample I chose to unwrap the result, which would panic if there was an error.在这个示例中,我选择解包结果,如果出现错误,这将导致恐慌。 However as pointed out by @shepmaster, the current implementation of write
on Vec
only ever returns an Ok
variant, so you could reduce the overhead of checking the result by discarding it like this:然而,正如@shepmaster 所指出的, 目前在Vec
上实现write
只会返回一个Ok
变体,因此您可以通过像这样丢弃它来减少检查结果的开销:
let _ = buff.write(&source);
Your example is extremely low-level;您的示例非常低级; it would help if you told us what high-level goal you want achieved, and we might be able to recommend an elegant way to do it in Rust.如果您告诉我们您想要实现的高级目标,那将会有所帮助,我们也许可以推荐一种在 Rust 中实现的优雅方法。
However, Rust is a systems language, so it's definitely possible to translate your code into Rust, just take into account that it: a) won't be safe, and b) won't be elegant.但是,Rust 是一种系统语言,因此绝对可以将您的代码翻译成 Rust,只要考虑到它:a) 不安全,b) 不优雅。 By not safe I mean you'll literally need to use unsafe
to allow unguarded writing to pointers, and figuratively that a bug might easily cause undefined behavior.所谓unsafe
,我的意思是您实际上需要使用unsafe
来允许不受保护地写入指针,并且比喻错误可能很容易导致未定义的行为。 And it's not elegant because there are usually nicer ways to achieve the same functionality.而且它并不优雅,因为通常有更好的方法来实现相同的功能。
With that said, here is a direct translation of the C code:话虽如此,这里是 C 代码的直接翻译:
use std::alloc::{self, Layout};
use std::{mem, ptr};
fn main() {
let source = [0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9];
unsafe {
let layout = Layout::from_size_align(10, mem::align_of::<i32>()).unwrap();
let buf = alloc::alloc(layout); // buf = malloc(10)
*(buf as *mut i32) = 6; // *(unsigned int *)buf = 6;
ptr::copy(source.as_ptr(), buf, 6); // memcpy(buf, source, 6);
// fill the rest of buf with something, otherwise UB on read
// use buf...
alloc::dealloc(buf, layout); // free(buf)
}
}
This kind of code is almost never normally written in Rust programs.这种代码几乎从不通常用 Rust 程序编写。 It is used in special situations, such as when implementing a crate that offers a safe abstraction not yet covered by existing crates, and reviewed with utmost care.它用于特殊情况,例如在实现提供现有 crate 尚未涵盖的安全抽象的 crate 时,并极其谨慎地进行审查。 For example, the code written in this answer originally contained a non-trivial bug kindly pointed out by a commenter (now fixed).例如,此答案中编写的代码最初包含一个评论者善意指出的重要错误(现已修复)。 Also, the code doesn't check for allocation failure (but neither did the original C code in the question).此外,该代码不会检查分配失败(但问题中的原始 C 代码也不会)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.