铸造到臂Cortex-M3上的双指针

wkftcu5l  于 2023-06-28  发布在  其他
关注(0)|答案(1)|浏览(99)

我使用的是Arm Cortex-M3处理器。我在unsigned char数组中接收二进制数据,必须将其转换为合适的变量以用于进一步计算:

unsigned char gps[24] = { 0xFA, 0x05, 0x08, 0x00, 0x10, 0x00,0xA4, 0x15, 0x02, 0x42, 0x4D, 0xDF, 0xEB, 0x3F, 0xF6, 0x1A, 0x36, 0xBE, 0xBF, 0x2D, 0xA4, 0x41,
                          0xAF, 0x1A };
int i = 6;
float f = (float) *(double*)&gps[i];

这段代码在计算机上工作,以获得正确的“f”值,但在Cortex-M3上失败。据我所知,没有一个算术单元的处理器,因此不支持64位操作;但是是否存在如上所示的用于铸造的工作区。
注意下面的代码在处理器上工作;只有上述铸件失效:

double d = 9.7;

还要注意32位强制转换可以工作,如下所示;只有doubleuint64_t失败。

uint16_t k = *(uint16_t*)&gps[i];

是否有其他解决方案?

5anewei6

5anewei61#

unsigned char的地址转换为指向double的指针-然后 * 使用 * 它-违反了strict aliasing rules;更重要的是(在您的情况下,如下所述),它还破坏了访问多字节所需的alignment rules(即double)数据单元。
许多编译器会对此发出警告; clang-cl为(double*)&gps[i]表达式提供了以下内容:
警告:从'unsigned char '到'double '的转换将所需的对齐方式从1增加到8 [-Wcast-align]
现在,一些架构对数据类型的对齐并不太挑剔,代码可能(似乎)可以在其中的许多类型上工作。然而,Cortex-M3对alignment requirements for multi-byte data types(例如double)非常挑剔。
要删除未定义的行为,您应该使用memcpy函数将gps数组的组件字节传输到
真实的
double变量中,然后将其转换为float

unsigned char gps[24] = {0xFA, 0x05, 0x08, 0x00, 0x10, 0x00,0xA4, 0x15, 0x02, 0x42, 0x4D,
        0xDF, 0xEB, 0x3F, 0xF6, 0x1A, 0x36, 0xBE, 0xBF, 0x2D, 0xA4, 0x41, 0xAF, 0x1A };
    int i = 6;
    double d; // This will be correctly aligned by the compiler
    memcpy(&d, &gps[i], sizeof(double)); // This doesn't need source alignment
    float f = (float)d; // ... so now, this is a 'safe' cast down to single precision

memcpy调用将使用(或生成)可以安全访问未对齐数据的代码--即使这意味着访问速度会显著降低。

相关问题