с помощью штуцера - это просто и легко
union
{
float f;
unsigned int ul;
unsigned char uc[4];
} myfloatun;
myfloatun.f=somenum;
printf("0x%08X\n",myfloatun.ul);
Гораздо безопаснее с точки зрения компилятора, чем указатели. Memcpy тоже отлично работает.
EDIT
Хорошо, хорошо, вот полностью функциональные примеры. Да, вы должны использовать объединения с осторожностью, если вы не следите за тем, как этот компилятор распределяет объединение и блокирует или выравнивает его, который он может сломать, и поэтому некоторые / многие говорят, что опасно использовать объединения таким способом. И все же альтернативы считаются безопасными?
У некоторого чтения C ++ есть свои проблемы с объединениями, и объединение вполне может просто не сработать. Если вы действительно имели в виду C ++, а не C, то это, вероятно, плохо. Если вы сказали «Клинекс» и имели в виду ткани, это может сработать.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef union
{
float f;
unsigned char uc[4];
} FUN;
void charRepresentation ( unsigned char *uc, float f)
{
FUN fun;
fun.f=f;
uc[0]=fun.uc[3];
uc[1]=fun.uc[2];
uc[2]=fun.uc[1];
uc[3]=fun.uc[0];
}
void floatRepresentation ( unsigned char *uc, float *f )
{
FUN fun;
fun.uc[3]=uc[0];
fun.uc[2]=uc[1];
fun.uc[1]=uc[2];
fun.uc[0]=uc[3];
*f=fun.f;
}
int main()
{
unsigned int ra;
float test;
char result[4];
FUN fun;
if(sizeof(fun)!=4)
{
printf("It aint gonna work!\n");
return(1);
}
test = 4.7567F;
charRepresentation(result,test);
for(ra=0;ra<4;ra++) printf("0x%02X ",(unsigned char)result[ra]); printf("\n");
test = 1.0F;
charRepresentation(result,test);
for(ra=0;ra<;ra++) printf("0x%02X ",(unsigned char)result[ra]); printf("\n");
test = 2.0F;
charRepresentation(result,test);
for(ra=0;ra<4;ra++) printf("0x%02X ",(unsigned char)result[ra]); printf("\n");
test = 3.0F;
charRepresentation(result,test);
for(ra=0;ra<4;ra++) printf("0x%02X ",(unsigned char)result[ra]); printf("\n");
test = 0.0F;
charRepresentation(result,test);
for(ra=0;ra<4;ra++) printf("0x%02X ",(unsigned char)result[ra]); printf("\n");
test = 0.15625F;
charRepresentation(result,test);
for(ra=0;ra<4;ra++) printf("0x%02X ",(unsigned char)result[ra]); printf("\n");
result[0]=0x3E;
result[1]=0xAA;
result[2]=0xAA;
result[3]=0xAB;
floatRepresentation(result,&test);
printf("%f\n",test);
return 0;
}
И вывод выглядит так
gcc fun.c -o fun
./fun
0x40 0x98 0x36 0xE3
0x3F 0x80 0x00 0x00
0x40 0x00 0x00 0x00
0x40 0x40 0x00 0x00
0x00 0x00 0x00 0x00
0x3E 0x20 0x00 0x00
0.333333
Вы можете проверить вручную или посмотреть на этот сайт, так как я взял примеры непосредственно с него, выходные данные соответствуют ожидаемым.
http://en.wikipedia.org/wiki/Single_precision
То, что вы никогда не хотите делать, - это указывать на память указателем, чтобы посмотреть на нее другим типом. Я никогда не понимал, почему эта практика используется так часто, особенно со структурами.
int broken_code ( void )
{
float test;
unsigned char *result
test = 4.567;
result=(unsigned char *)&test;
//do something with result here
test = 1.2345;
//do something with result here
return 0;
}
Этот код будет работать 99% времени, но не 100% времени. Он потерпит неудачу, когда вы меньше всего этого ожидаете и в самый неподходящий момент, например, на следующий день после того, как ваш самый важный клиент получит его. Это оптимизатор, который ест ваш обед с этим стилем кодирования. Да, я знаю, что большинство из вас делают это, и этому учили, и, возможно, никогда не сжигали ... пока. Это только делает его более болезненным, когда это, наконец, происходит, потому что теперь вы знаете, что оно может и не удалось (с популярными компиляторами, такими как gcc, на обычных компьютерах, таких как ПК).
Увидев этот сбой при использовании этого метода для тестирования процессора, программно создавая конкретные числа / шаблоны с плавающей запятой, я переключился на объединенный подход, который до сих пор никогда не подводил. По определению, элементы в объединении совместно используют один и тот же кусок памяти, и компилятор и оптимизатор не путаются, когда два элемента в этом общем блоке хранения находятся ... в одном и том же общем блоке хранения. С помощью приведенного выше кода вы полагаетесь на предположение о том, что за каждым использованием переменных имеется незарегистрированная память, и что все переменные записываются обратно в это хранилище перед следующей строкой кода. Хорошо, если вы никогда не оптимизируете или используете отладчик. В этом случае оптимизатор не знает, что результат и тестирование совместно используют один и тот же кусок памяти, и это является причиной проблемы / ошибки. Чтобы сделать игру с указателями, вам нужно поставить все на переменные, например, объединение, вам все еще нужно знать, как компилятор выравнивает и дополняет, вы все равно должны иметь дело с порядком байтов.
Проблема в том, что компилятор не знает, что эти два элемента находятся в одном и том же пространстве памяти. В приведенном выше конкретном тривиальном примере я наблюдал, как компилятор оптимизировал присвоение числа переменной с плавающей запятой, потому что это значение / переменная никогда не используется. Используется адрес для хранения этой переменной, и если вы скажете printf * * data result, компилятор не оптимизирует указатель результата и, следовательно, не оптимизирует адрес для тестирования и, следовательно, не оптимизирует хранилище для тестирования, но в этом простом примере это может произойти, когда числа 4.567 и 1.2345 никогда не попадут в скомпилированную программу. Я также видел, как компилятор выделяет хранилище для теста, но назначает числа в регистр с плавающей запятой, затем никогда не использует этот регистр и не копирует содержимое этого регистра в хранилище, которое он назначил. Причины, по которым это не удается для менее тривиальных примеров, могут быть труднее понять, часто связанные с распределением и удалением регистров, изменением строки кода, и это работает, изменением другой и разрывом.
Memcpy,
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void charRepresentation ( unsigned char *uc, float *f)
{
memcpy(uc,f,4);
}
void floatRepresentation ( unsigned char *uc, float *f )
{
memcpy(f,uc,4);
}
int main()
{
unsigned int ra;
float test;
unsigned char result[4];
ra=0;
if(sizeof(test)!=4) ra++;
if(sizeof(result)!=4) ra++;
if(ra)
{
printf("It aint gonna work\n");
return(1);
}
test = 4.7567F;
charRepresentation(result,&test);
printf("0x%02X ",(unsigned char)result[3]);
printf("0x%02X ",(unsigned char)result[2]);
printf("0x%02X ",(unsigned char)result[1]);
printf("0x%02X\n",(unsigned char)result[0]);
test = 0.15625F;
charRepresentation(result,&test);
printf("0x%02X ",(unsigned char)result[3]);
printf("0x%02X ",(unsigned char)result[2]);
printf("0x%02X ",(unsigned char)result[1]);
printf("0x%02X\n",(unsigned char)result[0]);
result[3]=0x3E;
result[2]=0xAA;
result[1]=0xAA;
result[0]=0xAB;
floatRepresentation(result,&test);
printf("%f\n",test);
return 0;
}
gcc fcopy.c -o fcopy
./fcopy
0x40 0x98 0x36 0xE3
0x3E 0x20 0x00 0x00
0.333333
С пламенем я расскажу о своих комментариях выше, и в зависимости от того, на какой стороне аргумента вы решите быть. Возможно, memcpy - ваш самый безопасный маршрут. Вы все еще должны очень хорошо знать компилятор и управлять своими порядками байтов. Компилятор не должен испортить memcpy, он должен сохранить регистры в памяти перед вызовом и выполнить по порядку.