使用 memcpy 转换字节数据

Converting byte data using memcpy

我正在尝试编写一个 C 程序来读取检测数据块并将特定字节提取到变量中。数据是混合格式,例如字节 4-5 是 integerbytes 10-14 是浮点数等。

我编写了一个实验程序来测试从字节 (char) 数组中提取值,但我不明白结果。我的测试程序是 运行 在 Raspberry Pi 3 运行 Debian Jessie 上。

这是我的程序:

将字节数组转换为部分

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main()
{

// Test Data Array
unsigned char v1[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                      0x40, 0xB1, 0x10, 0x55, 0xEE, 0x5A, 0xC7, 0x39,
                      0xBB, 0x22, 0x04, 0xB2, 0xF4, 0xF5, 0xF6, 0xF7,
                      0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFF, 0x87};

signed char        c; // 1-byte
unsigned char      u; // 1-byte
signed short       i; // 2-byte
unsigned  short    j; // 2-byte
signed int         k; // 4-byte
unsigned int       l; // 4-byte
signed long long   m; // 8-byte
unsigned long long n; // 8-byte
float              x; // 4-byte
double             y; // 8-byte
long double        z; // 8-byte

// Display type sizes
printf("\nsizeof's: %u %u %u %u %u   %u %u %u   \n\n",sizeof(char),
    sizeof(short),sizeof(int),sizeof(long),sizeof(long long),
    sizeof(float),sizeof(double),sizeof(long double));

printf("Addresses: \n");
printf("   %08X\n   %08X\n   %08X\n   %08X\n   %08X\n   %08X\n   %08X\n   %08X\n   %08X\n   %08X\n   %08X\n\n",
   &c,&u,&i,&j,&k,&l,&m,&n,&x,&y,&z);

// Display Endianess
unsigned int e1 = 1;
char *e2 = (char *)&e1;
if (*e2)
    printf("Little Endian\n\n");
else
    printf("Big Endian\n\n");

// Copy bytes to assorted variables

memcpy(&i,&v1[30],2);
printf("Signed Short:   %04X %hd\n",i,i); // FF 87

memcpy(&j,&v1[30],2);
printf("Unsigned Short: %04X %hu\n",j,j); // FF 87

memcpy(&k,&v1[16],4);
printf("Signed Int:     %08X %d\n",k,k);  // BB 22 04 B2

memcpy(&l,&v1[16],4);
printf("Unsigned Int:   %08X %u\n",l,l);  // BB 22 04 B2

memcpy(&x,&v1[8],4);
printf("Float:          %08X %f\n",x,x);  // 40 B1 10 55

memcpy(&y,&v1[8],8);
printf("Double:         %16X %lf\n",y,y);  // 40 B1 10 55 EE 5A C7 39

}

我得到的结果:

pi@raspberrypi:~/Desktop $ ./convertIt_bytes2

sizeof's: 1 2 4 4 8 4 8 8

Addresses: 7EA7E5DB 7EA7E5DA 7EA7E5D8 7EA7E5D6 7EA7E5D0 7EA7E5CC 7EA7E5C0 7EA7E5B8 7EA7E5B4 7EA7E5A8 7EA7E5A0

Little Endian

Signed Short: FFFF87FF -30721

Unsigned Short: 87FF 34815

Signed Int: B20422BB -1308351813

Unsigned Int: B20422BB 2986615483

Float: 7EA7E5E8 9943184834560.000000

Double: 7EA7E5EC 0.000000

memcpy 使用的字体大小从我打印的 sizeof's 看起来是正确的,那么为什么我的输出只有部分正确? Signed Short 十六进制值打印为 8 个字符而不是 4 个字符,即使它是一个用 %04X 打印的 2 字节字。

随后的 unsigned short 和 int 输出是正确的,但以下 float 和 double hex 值是垃圾并且似乎 addresses 不是值,因为输出接近上面打印的变量地址。这是怎么回事?

取以下内容:

memcpy(&i,&v1[30],2);
printf("Signed Short:   %04X %hd\n",i,i); // FF 87

将字符和短裤作为参数传递给可变参数函数,例如 printf 将导致这些参数隐式转换为整数。

i 是 "short"(16 位)。当它被传递给 printf 时,if 在进入堆栈之前被转换为 int(32 位)。这包括符号扩展。 0xff87 是一个负数(简称)。因此 0xff87 在打印之前被强制转换为 0xffffff87。

作为学习练习,试试这个:

printf("Signed Short:   %04X %hd\n",(unsigned short)i,(unsigned short) i); // FF 87

这将强制从 short 到 unsigned short 到 integer 的强制转换。这与从短整数到整数不同。

更新:既然你问了"printing a double value in hex form"。您基本上需要将保存该值的地址解释为十六进制字节数组。例如:

double d = 3.14159;
unsigned char* ptr = (unsigned char*)&d;
for (size_t i = 0; i < sizeof(double); i++)
    printf("%02x ", ptr[i]);

打印:

6e 86 1b f0 f9 21 09 40

字节顺序可能与您预期的不同,因为我 运行 在 x86 Intel 上。 Little Endian(或英特尔自己的特定布局)可能会影响浮点的内存字节顺序。