如何声明静态变量作为硬编码内存地址的引用?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何声明静态变量作为硬编码内存地址的引用?相关的知识,希望对你有一定的参考价值。

我正在为恩智浦的LPC82X系列控制器开发嵌入式Rust代码 - 确切的工具链对于这个问题无关紧要。

这些控制器包含ROM中的外设驱动程序我想使用这些驱动程序,这意味着我需要使用不安全的Rust和FFI而不链接实际代码。

ROM API将函数指针暴露在特定地址位置的C结构中。如果有人想要这个API的细节,the LPC82X manual的第29章描述了有问题的API。

我的Rust操场虚拟草图看起来像这样,通过一个尚未写入的I2C抽象lib从应用程序代码中隐藏。这编译。

#![feature(naked_functions)]

const I2C_ROM_API_ADDRESS: usize = 0x1fff_200c;
static mut ROM_I2C_API: Option<&RomI2cApi> = None;

#[repr(C)]
struct RomI2cApi {
    // Dummy functions, real ones take arguments, and have different return
    // These won't be called directly, only through the struct's implemented methods
    // value
    master_transmit_poll: extern "C" fn() -> bool,
    master_receive_poll: extern "C" fn() -> bool,
}

impl RomI2cApi {
    fn api_table() -> &'static RomI2cApi {
        unsafe {
            match ROM_I2C_API {
                None => RomI2cApi::new(),
                Some(table) => table,
            }
        }
    }

    unsafe fn new() -> &'static RomI2cApi {
        ROM_I2C_API = Some(&*(I2C_ROM_API_ADDRESS as *const RomI2cApi));
        ROM_I2C_API.unwrap()
    }

    #[inline]
    fn master_transmit_poll(&self) -> bool {
        (self.master_transmit_poll)()
    }

    #[inline]
    fn master_receive_poll(&self) -> bool {
        (self.master_receive_poll)()
    }
}

impl From<usize> for &'static RomI2cApi {
    fn from(address: usize) -> &'static RomI2cApi {
        unsafe { &*(address as *const RomI2cApi) }
    }
}

fn main() {
    let rom_api = unsafe { RomI2cApi::api_table() };
    println!("ROM I2C API address is: {:p}", rom_api);
    // Should be commented out when trying !
    rom_api.master_transmit_poll();
}

我不能将函数指针结构声明为非可变静态,因为静态有许多限制,包括不在引用中取消引用指针。有没有比Option更好的解决方法?使用Optionapi_table函数至少可以保证初始化的发生。

答案

你可以到处都有静电:

const ROM_I2C_API: &RomI2cApi = &*(0x1fff_200c as *const RomI2cApi);

还没有工作,但计划在未来工作。现在用

const ROM_I2C_API: *const RomI2cApi = 0x1fff_200c as *const RomI2cApi;

fn api_table() -> &'static RomI2cApi {
    unsafe { &*(ROM_I2C_API) }
}

这会创建一个&'static RomI2cApi,并允许您通过调用api_table().master_transmit_poll()直接访问各处的函数

以上是关于如何声明静态变量作为硬编码内存地址的引用?的主要内容,如果未能解决你的问题,请参考以下文章

类中声明的变量的内存分配

如何声明 Linq 表达式变量以便将其作为 dbParameter 处理

第16章:基址重定位

如何从 API 声明数组来代替硬编码数组?

如何在代码中创建一个“硬编码”的小 SQL 连接表?

java里的静态变量是放在了堆内存还是栈内存