memcpy не делает так, как положено - PullRequest
1 голос
/ 09 мая 2009

У меня есть этот бит кода, который выводит неправильные результаты.

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

int main() 
{
  unsigned char bytes[4];
  float flt=0;

  bytes[0]=0xde;
  bytes[1]=0xad;
  bytes[2]=0xbe;
  bytes[3]=0xef;

  memcpy( &flt, bytes, 4);

  printf("bytes 0x%x float %e\n", flt, flt);
  return 0;
}

вывод, который я получаю

байт 0xc0000000 с плавающей запятой -2.000001e + 00

Я ожидаю получить

байт 0xdeadbeef float -6.2598534e + 18

edit # 1 как было указано, порядок байтов может быть другим, что приведет к следующему

байт 0xefbeadde float -1.1802469e + 29

что я не понимаю, так это приведение от float к unsigned int, результатом которого является 0xc0000000 (float в том же операторе printf равен -2.0000, я бы отнес к оптимизации компилятора)

раньше это работало на другом компьютере. Это может быть изменение архитектуры.

Ответы [ 5 ]

8 голосов
/ 09 мая 2009

Это не проблема memcpy.

  1. float всегда преобразуется в double при передаче через ... printf, поэтому вы не можете получить 4 байта на большинстве архитектур Intel.
  2. когда вы указываете 0xdeadbeef в этом коде, вы предполагаете, что ваша архитектура имеет БОЛЬШОЙ порядок байтов. Существует много маленьких порядковых архитектур, например Intel x86.
6 голосов
/ 09 мая 2009

Вы понимаете, что числа с плавающей запятой увеличиваются в два раза при передаче в переменную функцию параметров, такую ​​как printf ()? Поэтому, когда вы говорите:

printf("bytes 0x%x float %e\n", flt, flt);

вы пытаетесь обработать то, что на самом деле два 8-байтовых значения, как два 4-байтовых значения, дающие (я считаю) неопределенное поведение.

2 голосов
/ 09 мая 2009

"% x" в printf ожидает беззнаковое целое. Вы даете ему float, который автоматически конвертируется, а это не то, что вам нужно. Вы хотите сделать что-то вроде:

printf("bytes 0x%x float %e\n", *((unsigned int *)&flt), flt);

О, и, как кто-то еще заметил, если вы используете x86, вы не увидите 0xdeadbeef, больше похоже на 0xefbeadde.

1 голос
/ 09 мая 2009

Чтобы увидеть продвижение параметра, измените объявление с плавающего на двойное. На моей машине это печатает:

bytes 0xefbeadde float -1.860545e+230

0xefbeadde - это big-endian для deadbeaf. Последние 4 байта двойного числа не определены, поэтому число, отображаемое после числа с плавающей запятой, будет различным.

Вы упомянули, что это работает на другом компьютере, что это за компьютер? Должно быть, был младший порядок, где sizeof (float) == sizeof (double):)

1 голос
/ 09 мая 2009

Посмотрите, лучше ли это:

printf("bytes 0x%x float %e\n", *(int *)&flt, flt);
...