堆栈上的 char 缓冲区/ASCII 字符串在 Rust 中的等价物是什么?
What is the Rust equivalent of a char buffer / ASCII string on the stack?
我正在尝试找到 Rust 等效于在堆栈上具有 ASCII 字符串缓冲区以具有与纯 C 代码相同的效率。
这里有一个简单的玩具练习的例子:
目标是生成一个随机内容和随机长度的 ASCII 字符串,最多 50 个字符长。因此,我在堆栈上保留了一个 char 缓冲区,用于迭代构造字符串。完成后,字符串将以恰到好处的 malloc 大小复制到堆上并返回给用户。
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#define ASCII_PRINTABLE_FIRST ' '
#define ASCII_PRINTABLE_AMOUNT 95
#define MAX_LEN 50
#define MAX_LEN_WITH_TERM (MAX_LEN + 1)
char* generate_string(void) {
char buffer[MAX_LEN_WITH_TERM];
srand((unsigned) time(NULL));
// Generate random string length
const int len = rand() % MAX_LEN_WITH_TERM;
int i;
for (i = 0; i < len; i++) {
// Fill with random ASCII printable character
buffer[i] = (char)
((rand() % ASCII_PRINTABLE_AMOUNT) + ASCII_PRINTABLE_FIRST);
}
buffer[i] = '[=10=]';
return strdup(buffer);
}
int main(void) {
printf("Generated string: %s\n", generate_string());
return 0;
}
到目前为止我探索的内容:
- 使用缓冲区
String::with_capacity(50)
或 BytesMut
,但这会在堆上分配缓冲区,我想避免这种情况。当然,这是过早的优化,但作为优化练习,让我们想象一下我调用 generate_string()
十亿次。这是十亿次 malloc 调用来分配缓冲区。我不想使用静态内存。
- 在堆栈上使用一个字符数组,但仅使用 ASCII 字符就消耗 space 的 4 倍
你有什么建议?
编辑:
- 是的,它泄漏了内存。这不是我问题的重点,除非你想要更长的代码片段。
- 是的,它有不安全的随机字符。这不是我问题的重点。
- 为什么我要在每次
generate_string()
调用时在堆上分配一次缓冲区?使功能自包含,无状态且没有静态内存。它不需要外部预分配的缓冲区。
相当于C的char
的Rust类型是u8
,所以相当于栈上的一个char
缓冲区是一个u8
数组。
let mut buf = [0u8; 20];
for i in 0..20 {
buf[i] = b'a' + i as u8;
}
要获取指向堆栈缓冲区的 &str
切片,您可以使用 std::str::from_utf8
,它执行 UTF-8 检查和 returns 指针(如果它是有效的 UTF) -8.
fn takes_a_string(a: &str) {
println!("{}", a);
}
fn main() {
let mut buf = [0u8; 20];
for i in 0..20 {
buf[i] = b'a' + i as u8;
}
// This calls takes_a_string with a reference to the stack buffer.
takes_a_string(std::str::from_utf8(&buf).unwrap());
}
abcdefghijklmnopqrst
您可以生成一个随机长度的 u8
数组(存储在堆栈中),并且仅在使用 from_utf8
方法将其转换为 String
时才在堆上分配内存。示例:
use rand::prelude::*;
const MAX_LEN: usize = 50;
const ASCII_START: u8 = 32;
const ASCII_END: u8 = 127;
fn generate_string() -> String {
let mut buffer = [0; MAX_LEN];
let mut rng = rand::thread_rng();
let buffer_len = rng.gen_range(0, MAX_LEN);
for i in 0..buffer_len {
buffer[i] = rng.gen_range(ASCII_START, ASCII_END);
}
String::from_utf8((&buffer[0..buffer_len]).to_vec()).unwrap()
}
fn main() {
for _ in 0..5 {
dbg!(generate_string());
}
}
我正在尝试找到 Rust 等效于在堆栈上具有 ASCII 字符串缓冲区以具有与纯 C 代码相同的效率。
这里有一个简单的玩具练习的例子: 目标是生成一个随机内容和随机长度的 ASCII 字符串,最多 50 个字符长。因此,我在堆栈上保留了一个 char 缓冲区,用于迭代构造字符串。完成后,字符串将以恰到好处的 malloc 大小复制到堆上并返回给用户。
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#define ASCII_PRINTABLE_FIRST ' '
#define ASCII_PRINTABLE_AMOUNT 95
#define MAX_LEN 50
#define MAX_LEN_WITH_TERM (MAX_LEN + 1)
char* generate_string(void) {
char buffer[MAX_LEN_WITH_TERM];
srand((unsigned) time(NULL));
// Generate random string length
const int len = rand() % MAX_LEN_WITH_TERM;
int i;
for (i = 0; i < len; i++) {
// Fill with random ASCII printable character
buffer[i] = (char)
((rand() % ASCII_PRINTABLE_AMOUNT) + ASCII_PRINTABLE_FIRST);
}
buffer[i] = '[=10=]';
return strdup(buffer);
}
int main(void) {
printf("Generated string: %s\n", generate_string());
return 0;
}
到目前为止我探索的内容:
- 使用缓冲区
String::with_capacity(50)
或BytesMut
,但这会在堆上分配缓冲区,我想避免这种情况。当然,这是过早的优化,但作为优化练习,让我们想象一下我调用generate_string()
十亿次。这是十亿次 malloc 调用来分配缓冲区。我不想使用静态内存。 - 在堆栈上使用一个字符数组,但仅使用 ASCII 字符就消耗 space 的 4 倍
你有什么建议?
编辑:
- 是的,它泄漏了内存。这不是我问题的重点,除非你想要更长的代码片段。
- 是的,它有不安全的随机字符。这不是我问题的重点。
- 为什么我要在每次
generate_string()
调用时在堆上分配一次缓冲区?使功能自包含,无状态且没有静态内存。它不需要外部预分配的缓冲区。
相当于C的char
的Rust类型是u8
,所以相当于栈上的一个char
缓冲区是一个u8
数组。
let mut buf = [0u8; 20];
for i in 0..20 {
buf[i] = b'a' + i as u8;
}
要获取指向堆栈缓冲区的 &str
切片,您可以使用 std::str::from_utf8
,它执行 UTF-8 检查和 returns 指针(如果它是有效的 UTF) -8.
fn takes_a_string(a: &str) {
println!("{}", a);
}
fn main() {
let mut buf = [0u8; 20];
for i in 0..20 {
buf[i] = b'a' + i as u8;
}
// This calls takes_a_string with a reference to the stack buffer.
takes_a_string(std::str::from_utf8(&buf).unwrap());
}
abcdefghijklmnopqrst
您可以生成一个随机长度的 u8
数组(存储在堆栈中),并且仅在使用 from_utf8
方法将其转换为 String
时才在堆上分配内存。示例:
use rand::prelude::*;
const MAX_LEN: usize = 50;
const ASCII_START: u8 = 32;
const ASCII_END: u8 = 127;
fn generate_string() -> String {
let mut buffer = [0; MAX_LEN];
let mut rng = rand::thread_rng();
let buffer_len = rng.gen_range(0, MAX_LEN);
for i in 0..buffer_len {
buffer[i] = rng.gen_range(ASCII_START, ASCII_END);
}
String::from_utf8((&buffer[0..buffer_len]).to_vec()).unwrap()
}
fn main() {
for _ in 0..5 {
dbg!(generate_string());
}
}