将地址存储为值并稍后在指针上使用它
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
。
这里有什么问题?
如何将数组的指针存储为一个值,发送它,成功地将它重铸为数组的地址并执行memcpy
?
为什么要存入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;
我正在尝试模拟一个需要将数据复制到外围设备的系统,裸机,没有 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
。
这里有什么问题?
如何将数组的指针存储为一个值,发送它,成功地将它重铸为数组的地址并执行
memcpy
?
为什么要存入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;