简体   繁体   English

如何将复制整数值长度后跟由该值组成的字节字符串的 C 代码转换为任意字节?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM