用于可变宽度访问的类型转换数组
Typecasting Arrays for Variable Width Access
抱歉,我不确定我写的标题是否准确。
但首先,这是我的限制条件:
- Array[],用作寄存器映射,声明为无符号8位数组(uint8_t),
这样索引(偏移量)是按字节计算的。
- 要 read/written 进入数组的数据具有不同的宽度(8 位、16 位、32 位和 64 位)。
- 非常有限的内存和速度是必须的。
执行以下操作有哪些注意事项
uint8_t some_function(uint16_t offset_addr) //16bit address
{
uint8_t Array[0x100];
uint8_t data_byte = 0xAA;
uint16_t data_word;
uint32_t data_double = 0xBEEFFACE;
\ A. Storing wider-data into the array
*((uint32_t *) &Array[offset_addr]) = data_double;
\ B. Reading multiple-bytes from the array
data_word = *((uint16_t *) &Array[offset_addr]);
return 0;
}
我知道我可以尝试按字节写入数据,但由于位移,这会很慢。
这种用法会出现严重问题吗?
我的硬件上有 运行 这个,到目前为止还没有发现任何问题,但我想注意这个实现可能导致的潜在问题。
这可能没问题。许多人都做过这样的事情。 C在这种事情上表现很好。
需要注意两点:
缓冲区溢出。你知道像永恒之蓝这样的零日攻击和像 WannaCry 这样的黑客攻击吗?他们中的许多人都利用了像您这样的代码中的错误。恶意输入导致代码向 uint8_t Array[0x100]
之类的数据结构中写入过多内容。当心。避免像您所做的那样在堆栈上分配缓冲区(作为函数局部变量),因为破坏堆栈是可利用的。让它们足够大。检查你没有超过它们。
机器字节排序与网络字节排序,又名 endianness。如果这些数据结构通过网络从一台机器移动到另一台机器,您可能会遇到麻烦。
Is there going to be a significant problem with this usage?
它会产生未定义的行为。因此,即使在实践中按照您对当前 C 实现、硬件、程序和数据的预期表现,您也可能会发现当某事(任何)发生变化时它会意外中断。
即使编译器以明显的方式实现转换和取消引用(它没有义务这样做,因为 UB),您的方法导致的未对齐访问至少会减慢许多 CPU,并且会在某些 CPU 上产生陷阱。
做你想做的符合标准的方法是这样的:
uint8_t some_function(uint16_t offset_addr) {
uint8_t Array[0x100];
uint8_t data_byte = 0xAA;
uint16_t data_word;
uint32_t data_double = 0xBEEFFACE;
\ A. Storing wider-data into the array
memcpy(Array + offset_addr, &data_double, sizeof data_double);
\ B. Reading multiple-bytes from the array
memcpy(&data_word, Array + offset_addr, sizeof data_word);
return 0;
}
这不一定比您的版本慢,只要您不超出数组的范围,它就会定义行为。
抱歉,我不确定我写的标题是否准确。
但首先,这是我的限制条件:
- Array[],用作寄存器映射,声明为无符号8位数组(uint8_t), 这样索引(偏移量)是按字节计算的。
- 要 read/written 进入数组的数据具有不同的宽度(8 位、16 位、32 位和 64 位)。
- 非常有限的内存和速度是必须的。
执行以下操作有哪些注意事项
uint8_t some_function(uint16_t offset_addr) //16bit address
{
uint8_t Array[0x100];
uint8_t data_byte = 0xAA;
uint16_t data_word;
uint32_t data_double = 0xBEEFFACE;
\ A. Storing wider-data into the array
*((uint32_t *) &Array[offset_addr]) = data_double;
\ B. Reading multiple-bytes from the array
data_word = *((uint16_t *) &Array[offset_addr]);
return 0;
}
我知道我可以尝试按字节写入数据,但由于位移,这会很慢。
这种用法会出现严重问题吗? 我的硬件上有 运行 这个,到目前为止还没有发现任何问题,但我想注意这个实现可能导致的潜在问题。
这可能没问题。许多人都做过这样的事情。 C在这种事情上表现很好。
需要注意两点:
缓冲区溢出。你知道像永恒之蓝这样的零日攻击和像 WannaCry 这样的黑客攻击吗?他们中的许多人都利用了像您这样的代码中的错误。恶意输入导致代码向
uint8_t Array[0x100]
之类的数据结构中写入过多内容。当心。避免像您所做的那样在堆栈上分配缓冲区(作为函数局部变量),因为破坏堆栈是可利用的。让它们足够大。检查你没有超过它们。机器字节排序与网络字节排序,又名 endianness。如果这些数据结构通过网络从一台机器移动到另一台机器,您可能会遇到麻烦。
Is there going to be a significant problem with this usage?
它会产生未定义的行为。因此,即使在实践中按照您对当前 C 实现、硬件、程序和数据的预期表现,您也可能会发现当某事(任何)发生变化时它会意外中断。
即使编译器以明显的方式实现转换和取消引用(它没有义务这样做,因为 UB),您的方法导致的未对齐访问至少会减慢许多 CPU,并且会在某些 CPU 上产生陷阱。
做你想做的符合标准的方法是这样的:
uint8_t some_function(uint16_t offset_addr) {
uint8_t Array[0x100];
uint8_t data_byte = 0xAA;
uint16_t data_word;
uint32_t data_double = 0xBEEFFACE;
\ A. Storing wider-data into the array
memcpy(Array + offset_addr, &data_double, sizeof data_double);
\ B. Reading multiple-bytes from the array
memcpy(&data_word, Array + offset_addr, sizeof data_word);
return 0;
}
这不一定比您的版本慢,只要您不超出数组的范围,它就会定义行为。