如何将 Rust 内存分配器用于可提供分配器的 C 库?

2023-11-23

我正在编写与 C 库的 Rust 绑定,该库可以选择使用第三方内存分配器。它的界面如下所示:

struct allocator {
    void*(*alloc)(void *old, uint);
    void(*free)(void*);
};

我猜,相应的 Rust 结构如下:

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Allocator {
    alloc: Option<extern "C" fn(*mut c_void, c_uint) -> *mut c_void>,
    free: Option<extern "C" fn(*mut c_void)>,
}

我如何实现这两个模拟分配器的外部函数?我没有找到任何真正像 Rust 中的分配器 API 的东西(但是我明白为什么),所以我很好奇它是否可能。


这并不像您希望的那么容易。

分配方法公开在heap的模块alloc crate.

创建一些包装器方法并填充结构很简单,但我们很快遇到了一个问题:

#![feature(heap_api)]

extern crate libc;
extern crate alloc;

use libc::{c_void, c_uint};
use alloc::heap;

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Allocator {
    alloc: Option<extern "C" fn(*mut c_void, c_uint) -> *mut c_void>,
    free: Option<extern "C" fn(*mut c_void)>,
}


extern "C" fn alloc_ext(old: *mut c_void, size: c_uint) -> *mut c_void {
    if old.is_null() {
        heap::allocate(size as usize, align) as *mut c_void
    } else {
        heap::reallocate(old as *mut u8, old_size, size as usize, align) as *mut c_void
    }
}

extern "C" fn free_ext(old: *mut c_void) {
    heap::deallocate(old as *mut u8, old_size, align);
}

fn main() {
    Allocator {
        alloc: Some(alloc_ext),
        free: Some(free_ext),
    };
}

Rust 分配器期望被告知任何先前分配的大小以及所需的对齐方式。您匹配的 API 没有任何方式传递该信息。

结盟should(我不是专家)可以硬编码某个值,比如 16 个字节。尺寸比较棘手。您可能需要借鉴一些旧的 C 技巧并分配一点额外的空间来存储大小。然后您可以存储大小并返回一个刚刚过去的指针。

A 完全未经测试例子:

#![feature(alloc, heap_api)]

extern crate libc;
extern crate alloc;

use libc::{c_void, c_uint};
use alloc::heap;
use std::{mem, ptr};

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Allocator {
    alloc: Option<extern "C" fn(*mut c_void, c_uint) -> *mut c_void>,
    free: Option<extern "C" fn(*mut c_void)>,
}

const ALIGNMENT: usize = 16;

extern "C" fn alloc_ext(old: *mut c_void, size: c_uint) -> *mut c_void {
    unsafe {
        // Should check for integer overflow
        let size_size = mem::size_of::<usize>();
        let size = size as usize + size_size;

        let memory = if old.is_null() {
            heap::allocate(size, ALIGNMENT)
        } else {
            let old = old as *mut u8;
            let old = old.offset(-(size_size as isize));
            let old_size = *(old as *const usize);
            heap::reallocate(old, old_size, size, ALIGNMENT)
        };

        *(memory as *mut usize) = size;
        memory.offset(size_size as isize) as *mut c_void
    }
}

extern "C" fn free_ext(old: *mut c_void) {
    if old.is_null() { return }

    unsafe {
        let size_size = mem::size_of::<usize>();

        let old = old as *mut u8;
        let old = old.offset(-(size_size as isize));
        let old_size = *(old as *const usize);

        heap::deallocate(old as *mut u8, old_size, ALIGNMENT);
    }
}

fn main() {
    Allocator {
        alloc: Some(alloc_ext),
        free: Some(free_ext),
    };

    let pointer = alloc_ext(ptr::null_mut(), 54);
    let pointer = alloc_ext(pointer, 105);
    free_ext(pointer);
}

难道不是[...using Vec作为分配者...] 更高级的解决方案?

这当然是可能的,但我不完全确定它如何与重新分配一起工作。您还必须跟踪设备的大小和容量Vec为了重构它以重新分配/删除它。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将 Rust 内存分配器用于可提供分配器的 C 库? 的相关文章

  • 通过 CMIS (dotCMIS) 连接到 SP2010:异常未经授权

    我正在使用 dotCMIS 并且想要简单连接到我的 SP2010 服务器 我尝试用 C 来做到这一点 如下所示http chemistry apache org dotnet getting started with dotcmis htm
  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • 查找c中结构元素的偏移量

    struct a struct b int i float j x struct c int k float l y z 谁能解释一下如何找到偏移量int k这样我们就可以找到地址int i Use offsetof 找到从开始处的偏移量z
  • 类模板参数推导 - clang 和 gcc 不同

    下面的代码使用 gcc 编译 但不使用 clang 编译 https godbolt org z ttqGuL template
  • 用于登录 .NET 的堆栈跟踪

    我编写了一个 logger exceptionfactory 模块 它使用 System Diagnostics StackTrace 从调用方法及其声明类型中获取属性 但我注意到 如果我在 Visual Studio 之外以发布模式运行代
  • 将 VSIX 功能添加到 C# 类库

    我有一个现有的单文件生成器 位于 C 类库中 如何将 VSIX 项目级功能添加到此项目 最终目标是编译我的类库项目并获得 VSIX 我实际上是在回答我自己的问题 这与Visual Studio 2017 中的单文件生成器更改 https s
  • 在 ASP.NET 5 中使用 DI 调用构造函数时解决依赖关系

    Web 上似乎充斥着如何在 ASP NET 5 中使用 DI 的示例 但没有一个示例显示如何调用构造函数并解决依赖关系 以下只是众多案例之一 http social technet microsoft com wiki contents a
  • 使用 WebClient 时出现 System.Net.WebException:无法创建 SSL/TLS 安全通道

    当我执行以下代码时 System Net ServicePointManager ServerCertificateValidationCallback sender certificate chain errors gt return t
  • C++ OpenSSL 导出私钥

    到目前为止 我成功地使用了 SSL 但遇到了令人困惑的障碍 我生成了 RSA 密钥对 之前使用 PEM write bio RSAPrivateKey 来导出它们 然而 手册页声称该格式已经过时 实际上它看起来与通常的 PEM 格式不同 相
  • 创建链表而不将节点声明为指针

    我已经在谷歌和一些教科书上搜索了很长一段时间 我似乎无法理解为什么在构建链表时 节点需要是指针 例如 如果我有一个节点定义为 typedef struct Node int value struct Node next Node 为什么为了
  • 使用 Bearer Token 访问 IdentityServer4 上受保护的 API

    我试图寻找此问题的解决方案 但尚未找到正确的搜索文本 我的问题是 如何配置我的 IdentityServer 以便它也可以接受 授权带有 BearerTokens 的 Api 请求 我已经配置并运行了 IdentityServer4 我还在
  • SolrNet连接说明

    为什么 SolrNet 连接的容器保持静态 这是一个非常大的错误 因为当我们在应用程序中向应用程序发送异步请求时 SolrNet 会表现异常 在 SolrNet 中如何避免这个问题 class P static void M string
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • 对现有视频添加水印

    我正在寻找一种用 C 在视频上加水印的方法 就像在上面写文字一样 图片或文字标签 我该怎么做 谢谢 您可以使用 Nreco 视频转换器 代码看起来像 NReco VideoConverter FFMpegConverter wrap new
  • cmake 将标头包含到每个源文件中

    其实我有一个简单的问题 但找不到答案 也许你可以给我指一个副本 所以 问题是 是否可以告诉 cmake 指示编译器在每个源文件的开头自动包含一些头文件 这样就不需要放置 include foo h 了 谢谢 CMake 没有针对此特定用例的
  • 如何在Xamarin中删除ViewTreeObserver?

    假设我需要获取并设置视图的高度 在 Android 中 众所周知 只有在绘制视图之后才能获取视图高度 如果您使用 Java 有很多答案 最著名的方法之一如下 取自这个答案 https stackoverflow com a 24035591
  • Rust 中声明变量的宏?

    在 C 中 可以编写声明变量的宏 如下所示 define VARS a b c int a b c 当然 这不是您通常想要做的事情 在实际的例子中 我希望开始工作 但它并不那么简单 define VARS data stride a b c
  • 将控制台重定向到 .NET 程序中的字符串

    如何重定向写入控制台的任何内容以写入字符串 对于您自己的流程 Console SetOut http msdn microsoft com en us library system console setout aspx并将其重定向到构建在
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • 如何实现仅当可用内存较低时才将数据交换到磁盘的写缓存

    我想将应用程序生成的数据缓存在内存中 但如果内存变得稀缺 我想将数据交换到磁盘 理想情况下 我希望虚拟机通知它需要内存并将我的数据写入磁盘并以这种方式释放一些内存 但我没有看到任何方法以通知我的方式将自己挂接到虚拟机中before an O

随机推荐

  • Django Rest Framework 每个视图的自定义权限

    我想在 Django Rest Framework 中基于视图 方法 用户权限创建权限 有没有一种方法可以实现这一目标 而无需手动编写每个权限并检查用户所在组的权限 另外 我面临的另一个问题是权限对象与某个模型相关联 由于我有影响不同模型的
  • UIAppearance 删除 UIPopoverController 的自定义导航栏背景

    我正在整合 iOS 5 的 UIAppearance 功能 为我的通用应用程序提供独特的主题 目前 我已经在我的应用程序委托中实现了一些代码来为应用程序提供自定义导航栏 UIImage navBarImage UIImage imageNa
  • Git:所有分支的默认“无提交”合并行为?

    我希望 git merge 默认情况下不提交 即 我希望默认情况下 no commit 行为 无论目标分支如何 我知道特定分支的 git config Branch master mergeoptions 并且我知道默认情况下禁用所有分支上
  • 在 Django 中发送电子邮件的连接超时问题

    我读自 http www packtpub com article friends via email social web application django 1 0 并按照以下步骤操作 gt 并改变我的 设置 py SITE HOST
  • 在anaconda3中安装openCV - Python.h:没有这样的文件或目录

    我正在尝试为我的 anaconda3 安装构建 opencv 3 1 0 但我的构建失败 94 Building CXX object modules python3 CMakeFiles opencv python3 dir src2 c
  • 使用 CLI 清除客户端缓存

    我们正在使用aurelia cli 任务包括 build json build ts process css ts process markup ts process sass ts run json run ts test json te
  • Scrapy PyInstaller OSError:无法获取源代码/twisted.internet.defer._DefGen_Return

    我正在尝试使用 PyInstaller 将一个非常简单的 Scrapy 蜘蛛发布为 EXE 文件 我已经搜索并阅读了我能找到的所有内容 但我仍然无法弄清楚出了什么问题 我怎样才能解决这个问题 如果我将yield更改为return 它不会给我
  • 在 Freemarker 宏中模拟空参数

    我正在使用 Freemarker 构建一个网站 并开始大量使用宏 我知道在 Freemarker 2 3 中 将 null 值作为参数传递到宏中相当于根本不传递参数 因此我创建了一个名为 null 的全局变量来模拟宏中的 null 检查 l
  • C 预处理器将“int x”拆分为 int & x

    我需要能够获得以下内容 define MY MACRO PARAM1 PARAM2 MY OTHER MACRO TYPENAME OF PARAM1 PARAMNAME OF PARAM1 MY OTHER MACRO TYPENAME
  • 集合的伪随机遍历

    我一直在读游戏编码完成 第四版 我在理解第 3 章 有用东西的抓取袋 部分中的 集合的伪随机遍历 路径时遇到了一些问题 您是否想知道 CD 播放机上的 随机 按钮是如何工作的 它会随机播放 CD 上的每首歌曲 而不会播放同一首歌曲两次 这是
  • android tv - 重新加载适配器数据

    我想重新加载浏览片段中的一些行数据 基本上我想重置适配器数据而不在浏览片段中造成类似闪存的效果 知道如何做到吗 就像是notifyDataSetChanged 在列表视图中 Thanx 这将刷新数据而不丢失当前位置 for int i 0
  • 监视 Windows 中进程执行的某些系统调用

    我希望能够监视进程进行的某些系统调用 主要是文件 I O 调用 在Linux上我可能可以使用strace具有合适的参数 但如何在 Windows 上执行此操作 我主要感兴趣的是运行一个进程并找出它已读取和写入的文件 我想从另一个进程以编程方
  • 继承自Set.prototype

    这真的很困扰我 我可以轻松创建一个继承方法的新类Array prototype var MyArray function MyArray prototype Array prototype var myArray new MyArray m
  • 如何在 DDEV Web 容器中添加和使用 nvm?

    目前 DDEV Web 容器不附带 nvm 节点版本管理器 如何通过 DDEV config yaml 文件添加和使用它 在当前的 ddev v1 19 中 默认安装了 nvm 并且可以与ddev nvm 所以您不必执行任何操作 看docs
  • Python:导入模块导入模块

    所以在文件 foo 中我导入模块 import lib helper functions import lib config 在 helper functions py 中 我有 import config 当我运行 foo 的 main
  • Jmeter中的吞吐量计算

    Attached is the Summary Report for my tests 请帮我理解JMeter的吞吐量值是如何计算的 例如第一条线路的吞吐量53 1 min 这个数字是JMeter用什么公式计算出来的 另外 想知道后续测试中
  • 我如何通过 Objective-c 访问 iPhone 文件?

    我注意到有一些软件 例如 iExplorer 可以让您从 Mac 访问 iPhone 设备上的文件 现在我的问题是 如何通过 Objective c 访问 iPhone 文件 这仅用于教育目的 我找到了这个 https github com
  • 如何知道应用程序运行在什么 Mac 操作系统上?

    我在一些项目中看到过类似的东西 if code endif 但我现在找不到了 例如 如果应用程序在 10 8 上运行 则该应用程序会执行 1 件事 否则该应用程序会执行其他操作 编写什么代码来检查它是否在 10 8 上运行 Thanks 你
  • Mod重写问题

    和其他许多人一样 我在 apache 中进行一些非常简单的 mod rewriting 时遇到了问题 我的 htaccess 中有以下内容 Options FollowSymLinks RewriteEngine on RewriteBas
  • 如何将 Rust 内存分配器用于可提供分配器的 C 库?

    我正在编写与 C 库的 Rust 绑定 该库可以选择使用第三方内存分配器 它的界面如下所示 struct allocator void alloc void old uint void free void 我猜 相应的 Rust 结构如下