将地址存储为值并稍后在指针上使用它

Store address as value and use it later on pointer

我正在尝试模拟一个需要将数据复制到外围设备的系统,裸机,没有 OS。

约定俗成的copy函数是一个C函数,它把一个8位的地址作为外设的地址写入某个寄存器。外围设备在内部使用它。但是,我正在用 C 语言模拟这个东西并测试我正在做的全部功能,比如下面的 MWE:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc,char *argv[]){

    //stack-array to copy
    char array[4] = {3,32,-12,99};
    //naive emulation of the peripheral memory space
    char peripheral_array[4];

    //herein lies the address send as a value
    char address_reg = (char*)(peripheral_array);

    //assume this is the peripheral side
    //set ptr to the address of the peripheral_array
    char *ptr = (char*) address_reg;
    memcpy((void*)ptr,array,sizeof(char)*4);

    return EXIT_SUCCESS;
}

我得到 segmentation fault

为什么要存入char?可以保存 char 地址的变量是 char* - 在两台机器上 - 您的 PC 和嵌入式 MCU!

在你的 MCU 上 sizeof(char*) 可能是 1 或 2,在你的 PC 上可能是 4 或 8;

如果要编写平台兼容代码,请使用 char*

如果您想进一步模拟机器地址 space,那么您必须提供自己的 standard-lib 函数实现。这样他们就可以将机器地址 space 中的地址解释为您定义的某些内存数组的索引。

然而,更好的方法主要是提供一些封装系统特定任务的硬件抽象层 (HAL),而不是在您的业务逻辑中使用机器规范。

您想在具有 32 位或 64 位地址 space 的环境中模拟具有 8 位地址 space 的东西,因此您遇到了一些困难,因为它没有' 平凡地转换。具体来说,这一行 char address_reg = (char*)(peripheral_array) 将一个宽指针转换为一个 8 位值,并丢失了大部分指针,这意味着您将无法转换回来。

解决方案是进一步推进您的模拟并模拟您的目标 8 位地址 space :

  • Typedef 一个 8 位指针(更干净):typedef uint8_t ptr8;
  • 声明您的 8 位目标地址 space : uint8_t my_destination_memory[256]
  • 定义你自己的memcpy复制到这个地址space:
    void my_memcpy( ptr8 addr_dest, const void * src, int len ) {
        memcpy( my_destination_memory + addr_dest, src, len );
    }
    

这样你就可以传递类型为 ptr8(或任何你命名的)的 8 位指针并毫无问题地复制到它。
请注意,我假设您的源地址 space 并不重要,但如果它是您也可以模拟它。您应该能够以相同的方式模拟 16 位甚至 24 位地址 space(如果需要 32 位,您可以使用本机指针)。

首先,请注意在 char 类型中存储整数值是危险的,因为它是具有 implementation-defined 符号的类型。它不应该用于字符串以外的任何东西。

相反,始终使用 int8_t(有符号)或 uint8_t(无符号)。


问题的原因是 char(或 int8_t 就此而言)不够大,无法容纳地址。

然而 stdint.h 中的 uintptr_t 保证足够大以包含地址。

简单替换

char address_reg = (char*)(peripheral_array);

uintptr_t address_reg = (uintptr_t)peripheral_array;