数据转换:将数组中的 4 字节数据分配给 1 字节数组
Data conversion: Assigning 4 byte data from array into 1 byte array
首先,让我稍微解释一下环境。我正在为嵌入式 32 位微控制器使用 C。通过各种工具进行单元测试,但结果是一样的。 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。同样。
校准数据为 1.0。这将成为 1 作为 uint32。
因此数据将显示为:
Data[0] = 0
Data[1] = 0
Data[2] = 0
Data[3] = 1
如果我使用的是方法 2,则代码会在数据中显示垃圾值。
请告诉我更好的方法或改进上述方法之一。
此致
错误是转换 (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];
最后一个选项有两个主要优点:
- 它是预先可以理解的,行数越少越好。
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++;
}
首先,让我稍微解释一下环境。我正在为嵌入式 32 位微控制器使用 C。通过各种工具进行单元测试,但结果是一样的。 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。同样。 校准数据为 1.0。这将成为 1 作为 uint32。
因此数据将显示为:
Data[0] = 0
Data[1] = 0
Data[2] = 0
Data[3] = 1
如果我使用的是方法 2,则代码会在数据中显示垃圾值。
请告诉我更好的方法或改进上述方法之一。
此致
错误是转换 (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];
最后一个选项有两个主要优点:
- 它是预先可以理解的,行数越少越好。
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++;
}