在C中将偏移的字节数组转换为int32数组

时间:2015-08-08 10:36:50

标签: c embedded stm32 iar

背景 我正在使用IAR Embedded Workbench IDE和在STM32F091(ARM Cortex-M0内核)微控制器上运行的工具链,使用C语言编写嵌入式应用程序。该应用程序将数据写入微控制器嵌入式闪存,其中只能输入32位字(也许半字也可以工作)。

问题描述 数据存储在uint8_t字节类型数组中,前面是一些头信息(在本例中是来自板载调制解调器的AT响应代码),不应写入闪存。我想发送一个uint32_t指针指向uint8_t缓冲区中实际数据的起始位置。但是如果这个偏移不是4字节对齐,我的应用程序崩溃,因为它试图访问未对齐的uint32_t类型。

这描述了我正在尝试做的事情(不是真正的代码,只是一个例子):

uint8_t modemResponseBuffer[MAX_MODEM_RESPONSE_SIZE];

/* Get the modem response data (including modem response header data) */
size_t modemResponseSize = GetModemResponseData(modemResponseBuffer);

/* Get the actual data size from the header information */
size_t dataSize = GetActualDataSizeFromModemResponseHeader(modemResponseBuffer);

/* Get the offset to where the actual data starts in the modem response */
size_t modemDataOffset = GetModemResponseDataOffset(modemResponseBuffer);

/* Write the data part of the response to embedded flash memory. 
The modemDataOffset can be any number which messes up 4 byte data alignment */
ProgramFlashMemory(DATA_FLASH_STORAGE_ADDRESS, (uint32_t*)&modemResponseBuffer[modemDataoffset],
 dataSize);

ProgramFlashMemory 函数内部,循环调用 FLASH_ProgramWord 标准外设库函数。

问题(S) 如何有效地解决这个问题?我正在研究一个系统,我的内存有限(32 kb RAM),所以我不希望将所需的内容从uint8_t缓冲区复制到uint32_t类型的新缓冲区。目前我通过循环手动对齐数据,但这对我来说似乎相当笨拙。但我还没有提出更好的解决方案,我对我可能会收到的建议感兴趣。

此外,如果有人知道,我也想知道为什么应用程序在这种情况下崩溃。我的核心(或任何核心?)无法处理未对齐数据类型的原因是什么?

3 个答案:

答案 0 :(得分:3)

更改ProgramFlashMemory()以获取void*,然后在内部将其转换为uint8_t*,然后您将一次四个字节迭代到unit32_t,然后您写入闪光灯。

void*允许写入任何对象的地址而无需显式转换。

类似的东西:

int ProgramFlashMemory( uint32_t* addr, void* data, int length )
{
    int byte = 0 ;
    int word = 0 ;

    while( byte < length )
    {
        uint32_t flash_word = 0 ;

        // Copy four bytes to word
        // Note: little-endian byte order assumed,
        //       reverse for big-endian.  
        // If end is not aligned, fill with 0xff.
        for( b = 0; b < 4; b++ )
        {
            flash_word |= byte < length ? 
                          (uint8_t*)data[byte] << (b<<3) : 
                          0xFF ;
            byte++ ;
        }

        ProgramFlashWord( addr[word], flash_word ) ;
        word++ ;
    }

    // Return bytes written - may be linger than `length` by up-to 
    // three for end-alignment.
    return byte ;
}

您可能希望保留原始ProgramFlashMemory()以进行有效的对齐写入,在这种情况下可能ProgramFlashMemoryUnaligned()。请注意,它不仅仅是对齐,而且长度不一定能被4整除,需要注意。

答案 1 :(得分:1)

这假设在写入有效载荷数据后不再需要标题数据。

要确保缓冲区的对齐方式正确,您可能需要声明它:

uint32_t modemResponseBuffer[(MAX_MODEM_RESPONSE_SIZE * sizeof (uint8_t) / sizeof (uint32_t)) + 1];

在调用writer-function之前,只需将有效负载数据移动到缓冲区的开头:

memmove(modemResponseBuffer, modemResponseBuffer + modemDataoffset, dataSize);

请注意memcpy()在此处不起作为目的地和来源重叠。

然后像这样打电话给作家:

ProgramFlashMemory(DATA_FLASH_STORAGE_ADDRESS, modemResponseBuffer, dataSize);

答案 2 :(得分:1)

ARM Cortex-M0内核在未对齐访问时崩溃的原因是{{3}}。采用硬故障异常实际上是对某些较旧核心的改进,这些核心将错误地访问该值,然后继续以损坏的值执行。一些较新的ARM内核对未对齐访问的硬件支持有限。

以下是一些建议。

重新设计ProgramFlashMemory(),使其接受uint8_t*而不是uint32_t*。为了对单词进行编程,它应该将缓冲区中的各个字节复制到具有正确对齐的局部变量中。然后将局部变量副本写入flash。

重新设计GetModemResponseData(),以便在从流中读取标头时解析标头。它将在从流中读取数据之前确定标头的长度和数据的起始点。当流位于数据的开头时,它应该开始将数据复制到一个与标题分开的新缓冲区中并正确对齐。