我正在尝试模拟一个需要将数据复制到外设,裸机,没有操作系统的系统。
约定规定复制功能是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
。
这里有什么问题?
如何将数组指针存储为值,发送,将其成功重新编译为数组并执行memcpy
?
答案 0 :(得分:3)
您希望在具有32位或64位地址空间的环境中模拟具有8位地址空间的内容,因此您遇到一些困难,因为它不会轻易转换。具体来说,这一行char address_reg = (char*)(peripheral_array)
投射了一个指向8位值的宽指针,并丢失了大部分指针,这意味着你将无法转换回来。
解决方案是进一步推进模拟并模拟目标8位地址空间:
typedef uint8_t ptr8;
uint8_t my_destination_memory[256]
void my_memcpy( ptr8 addr_dest, const void * src, int len ) { memcpy( my_destination_memory + addr_dest, src, len ); }
通过这种方式,您可以传递ptr8
类型的8位指针(或任何您命名的指针)并将其复制到它上面。
请注意,我认为您的源地址空间不重要,因为您也可以模拟它。您应该能够以相同的方式模拟16位甚至24位地址空间(如果需要32位,可以使用本机指针)。
答案 1 :(得分:1)
为什么要将其存储到char
?可以将地址保存到char
的变量是char*
- 在两台机器上 - 您的PC和嵌入式MCU!
在您的MCU上sizeof(char*)
可能是1或2,而在您的PC上它可能是4或8;
如果您想编写与平台兼容的代码,请使用char*
。
如果您想进一步模拟机器地址空间,那么您必须提供标准-lib函数的自己实现。这样他们就可以将机器地址空间中的地址解释为您定义的某些内存数组的索引。
然而,更好的方法主要是提供一些硬件抽象层(HAL)来封装系统特定的任务,而不是在业务逻辑中使用机器特定的。
答案 2 :(得分:0)
首先,请注意,在char
类型中存储整数值是危险的,因为它是具有实现定义的签名的类型。除了字符串之外,它永远不应该被用于任何东西。
相反,请始终使用int8_t
(已签名)或uint8_t
(无签名)。
问题的原因是char
(或int8_t
对此问题而言)不足以容纳地址。
然而uintptr_t
中的stdint.h
保证足够大以包含地址。
简单地替换
char address_reg = (char*)(peripheral_array);
与
uintptr_t address_reg = (uintptr_t)peripheral_array;