使用memcpy转换字节数据

时间:2018-01-29 06:44:23

标签: c memcpy

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

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

这是我的计划:

将字节数组转换为部分

#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

     

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

     

Little Endian

     

签名短:FFFF87FF -30721

     

无符号短语:87FF 34815

     

签署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而不是值,因为输出接近上面打印的变量地址。发生了什么事?

1 个答案:

答案 0 :(得分:1)

采取以下措施:

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

将chars和short作为参数传递给变量参数函数(如printf)将导致这些参数被隐式转换为整数。

i&#34;简短&#34; (16位)。并且当它传递给printf时,如果在命中堆栈之前转换为int(32位)。这包括符号扩展。 0xff87是负数(简称)。因此,在打印之前,0xff87会被强制转换为0xffffff87。

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

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

这将强制从短到无符号短整数到整数。这与从短到整数不同。

更新:由于您询问&#34;以十六进制格式打印双精度值&#34;。您基本上需要将保存该值的地址解释为十六进制字节数组。例如:

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(或英特尔自己的特定布局)可能会影响浮点的内存中字节顺序。