数据转换:将数组中的4字节数据分配给1字节数组

问题描述 投票:0回答:1

首先,让我解释一下环境。我将C用于嵌入式32位微控制器。通过各种工具进行单元测试,但结果相同。 printf仅用于MinGW的测试。

我正在尝试将数据从float32数组(4字节数组)(IEEE754)复制到字节数组中。

我仅在这里使用十六进制数据,重要的是十六进制值的位置准确,即:

If CalibData[0] = 01 02 03 04

然后数据应该看起来像这样:

   Data[0] = 01
   Data[1] = 02
   Data[2] = 03
   Data[3] = 04

我能想到的可能性类似于下面提到的代码块:

/*CalibData is a Global variable and change by other components, I am only reading it here*/
float32 CalibData [1920];

/*Data is an argument for my function and shall return it with values read from CalibData*/
int Data[7680];

/* Approach 1: */

uint16_t dataElementCounter = 0;
for (uint16_t i = 0; i < 1920; i++)
{
Data[dataElementCounter] = (uint8) ((uint32) calib_Data[i] >> 24);
dataElementCounter++;
Data[dataElementCounter] = (uint8) ((uint32) calib_Data[i] >> 16);
dataElementCounter++;
Data[dataElementCounter] = (uint8) ((uint32) calib_Data[i] >> 8);
dataElementCounter++;
Data[dataElementCounter] = (uint8) ((uint32)calib_Data[i]);
dataElementCounter++;
}

/* Approach 2: */
for (uint16_t i = 0; i < 1920; i++)
{
memcpy((uint8*) Data[0], &calib_Data[i],sizeof(float));
}

现在的问题是,如果我正在使用方法1,那么很难在没有硬件的情况下测试数据是否已正确复制,因为通过单元测试或printf对其进行测试始终会提供截断的数据。例如

if CalibData[0] = 1.0;

根据IEEE754,十六进制应为0x3F 0x80 0x00 0x00,但在单元测试或printf中,它将像这样:

CalibData >> 24是分数1.0 /16777216。当转换为uint32时,它将截断为0。CalibData >> 16是分数1.0 /65536。同样。CalibData >> 8是分数1.0 /256。同样。CalibData为1.0。作为uint32,它将变为1。

所以数据将显示为:

Data[0] = 0
Data[1] = 0
Data[2] = 0
Data[3] = 1

如果我使用的是方法2,则代码将在Data中显示垃圾值。

请告诉我一种更好的方法或改进上述方法之一。

问候

embedded microcontroller generic-programming
1个回答
0
投票

由于将(uint32)转换为float而导致的错误uint32,这不是您想要的。

您最好的选择是此摘录:

union {
    float f;
    uint8 b[4];
} u;

u.f = calib_Data[i];
Data[dataElementCounter] = u.b[0];
dataElementCounter++;
Data[dataElementCounter] = u.b[1];
dataElementCounter++;
Data[dataElementCounter] = u.b[2];
dataElementCounter++;
Data[dataElementCounter] = u.b[3];
dataElementCounter++;

请注意,这不符合C标准。但是它可能会在您的实际系统上运行。

编辑1

仍然不符合要求,但不使用union,可以使用强制转换的指针来模拟:

const uint8* b = (const uint8*)(calib_Data + i); // equally, but simpler to read than &calib_Data[i]
Data[dataElementCounter] = b[0];
dataElementCounter++;
Data[dataElementCounter] = b[1];
dataElementCounter++;
Data[dataElementCounter] = b[2];
dataElementCounter++;
Data[dataElementCounter] = b[3];
dataElementCounter++;

这类似于codetest的答案,甚至更好地建议使用memcpy()

memcpy(Data + dataElementCounter, calib_Data + i, sizeof calib_Data[i]);
dataElementCounter += sizeof calib_Data[i];

最后一个选项有两个主要优点:

  1. 这是可以用最少的行来预先理解的。
  2. 防止更改calib_Data的数据类型的大小。

编辑2

要求:您必须交换字节。

如果目标系统是固定的,并且如果您完全确定自己在做什么,那么要做的第一件事就是在注释中记录下来。此外,您可能想检查编译器:

 #if !defined(MY_COMPILER_ID)
 #error Compiler not supported
 #endif

要以相反的顺序存储浮点数,可以使用带有反向索引的EDIT 1的第一种选择:

const uint8* b = (const uint8*)(calib_Data + i); // equally, but simpler to read than &calib_Data[i]
Data[dataElementCounter] = b[3];
dataElementCounter++;
Data[dataElementCounter] = b[2];
dataElementCounter++;
Data[dataElementCounter] = b[1];
dataElementCounter++;
Data[dataElementCounter] = b[0];
dataElementCounter++;

[为了使其在将来免受calib_Data数据类型大小的更改的影响,您需要一个循环:

const uint8* b = (const uint8*)(calib_Data + i); // equally, but simpler to read than &calib_Data[i]
int b_i;
for (b_i = sizeof calib_Data[i] - 1; b_i >= 0; --b_i) {
    Data[dataElementCounter] = b[b_i];
    dataElementCounter++;
}
© www.soinside.com 2019 - 2024. All rights reserved.