C 用于可变宽度访问的类型转换数组

C 用于可变宽度访问的类型转换数组,c,memory,casting,hardware,buffer-overrun,C,Memory,Casting,Hardware,Buffer Overrun,对不起,我不确定我写的标题是否准确 但首先,我的限制是: 用作寄存器映射的数组[]声明为无符号8位数组(uint8_t), 这使得索引(偏移量)是每字节的 要读取/写入阵列的数据具有不同的宽度(8位、16位、32位和64位) 必须具备非常有限的内存和速度 执行以下操作的注意事项是什么 uint8_t some_function(uint16_t offset_addr) //16bit address { uint8_t Array[0x100]; uint8_t data_byte =

对不起,我不确定我写的标题是否准确

但首先,我的限制是:

  • 用作寄存器映射的数组[]声明为无符号8位数组(uint8_t), 这使得索引(偏移量)是每字节的
  • 要读取/写入阵列的数据具有不同的宽度(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在这种事情上表现得很好

    要注意两件事:

  • 缓冲区溢出。你知道那些零度的日子,比如永恒的蓝色和像万纳克里那样的黑客吗?他们中的许多人利用了像您这样的代码中的bug。恶意输入导致代码将过多内容写入数据结构,如
    uint8\u t数组[0x100]
    。小心。避免像您所做的那样在堆栈上分配缓冲区(作为函数局部变量),因为对堆栈的破坏是可利用的。让它们足够大。检查你没有超过他们

  • 机器字节排序与网络字节排序,又名。如果这些数据结构通过网络从一台机器移动到另一台机器,您可能会遇到麻烦

  • 这种用法会有重大问题吗

    它产生未定义的行为。因此,即使在实践中,它在当前的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;
    }
    

    这并不一定比您的版本慢,而且只要您没有超出数组的边界,它就定义了行为。

    如果您想知道/询问的是,将指针强制转换为不同类型以进行宽度访问,实际上没有什么错。我不相信会有性能损失,因为操作是原子级的。相反,@Nina将指针强制转换为不兼容的类型,然后取消对它们的引用违反了严格的别名规则。未定义的行为结果。即使编译器只是做了明显的事情(它没有义务去做),这种方法导致的错误对齐将导致一些系统上的性能降低和一些其他系统的陷阱。这是有道理的。但是,如果您确实了解编译器的行为方式以及系统如何处理每个操作,那么应该没问题。是吗?如果您这样做,请注意,整个事情并不是由C标准定义的,因此您依赖于编译器供应商的善意或感谢您!数据结构的实际实现是在全球范围内的,因此它很可能位于.data部分。至于endianness,到目前为止,没有必要在不同的机器/系统上运行代码。不过,我会留意这些。真的很感激!网络爬虫也很容易攻击你的.data部分,让你的程序运行他们的恶意代码。保持警惕。(安全性是人们迁移到Java/c#/rust/python/go等语言的一个重要原因。)请放心,这台机器将无法访问互联网。哈哈。这是一个在fpga/软处理器上运行的低级程序。OK。但还是要小心。问题:如果我希望偏移量被视为不同的类型,而不是uint8,该怎么办?例如,我有一个uint16_t*数组,那么+2将是(sizeof(uint16_t)+2),但是我希望指针偏移量被视为uint8_t,因此在这种情况下,如果希望偏移量以
    uint8_t
    的大小进行解释,我可以执行
    memcpy((uint8_t*)数组+偏移量…
    是的@Nina,但是数组有一些更广泛的元素类型,那么您介绍的方法将实现这一点。