web-dev-qa-db-fra.com

Fonction C pour convertir float en tableau d'octets

J'essaie de créer une fonction qui acceptera une variable float et la convertira en tableau d'octets. J'ai trouvé un extrait de code qui fonctionne, mais j'aimerais le réutiliser dans une fonction si possible. 

Je travaille également avec l'environnement Arduino, mais je comprends qu'il accepte la plupart des langages C.

Travaille actuellement:

float_variable = 1.11;
byte bytes_array[4];

*((float *)bytes_array) = float_variable;

Que puis-je changer ici pour que cette fonction fonctionne?

float float_test = 1.11;
byte bytes[4];

// Calling the function
float2Bytes(&bytes,float_test);

// Function
void float2Bytes(byte* bytes_temp[4],float float_variable){ 
     *(float*)bytes_temp = float_variable;  
}

Je ne connais pas très bien les pointeurs, mais j'ai lu que (float ) utilise un casting ou quelque chose?

Toute aide serait grandement appréciée!

À votre santé

* EDIT: RESOLU

Voici ma fonction finale qui fonctionne dans Arduino pour quiconque trouve cela. Les réponses ci-dessous contiennent des solutions plus efficaces, mais je pense que cela peut être compris.

Fonction: convertit la variable float en entrée en tableau d'octets

void float2Bytes(float val,byte* bytes_array){
  // Create union of shared memory space
  union {
    float float_variable;
    byte temp_array[4];
  } u;
  // Overite bytes of union with float variable
  u.float_variable = val;
  // Assign bytes to input array
  memcpy(bytes_array, u.temp_array, 4);
}

Appeler la fonction 

float float_example = 1.11;
byte bytes[4];

float2Bytes(float_example,&bytes[0]);

Merci à tous pour votre aide. Au cours des 20 dernières minutes, j'ai beaucoup appris sur les pointeurs et les références, Cheers Stack Overflow!

16
Ben Winding

Le plus simple est de faire une union:

#include <stdio.h>

int main(void) {
  int ii;
  union {
    float a;
    unsigned char bytes[4];
  } thing;

  thing.a = 1.234;
  for (ii=0; ii<4; ii++) 
    printf ("byte %d is %02x\n", ii, thing.bytes[ii]);
  return 0;
}

Sortie:

byte 0 is b6
byte 1 is f3
byte 2 is 9d
byte 3 is 3f

Remarque - l'ordre des octets n'est pas garanti… cela dépend de l'architecture de votre machine.

Pour que votre fonction fonctionne, procédez comme suit:

void float2Bytes(byte* bytes_temp[4],float float_variable){ 
  union {
    float a;
    unsigned char bytes[4];
  } thing;
  thing.a = float_variable;
  memcpy(bytes_temp, thing.bytes, 4);
}

Ou pour vraiment le pirater:

void float2Bytes(byte* bytes_temp[4],float float_variable){ 
  memcpy(bytes_temp, (unsigned char*) (&float_variable), 4);
}

Remarque - dans les deux cas, je m'assure de copier les données à l'emplacement indiqué comme paramètre d'entrée. Ceci est crucial, car les variables locales n'existeront plus après votre retour (bien que vous puissiez les déclarer static, mais ne vous enseignons pas les mauvaises habitudes. Et si la fonction était appelée à nouveau…)

21
Floris

Voici une façon de faire ce que vous voulez, qui ne casse pas si vous êtes sur un système avec un endianness différent de celui sur lequel vous vous trouvez:

byte* floatToByteArray(float f) {
    byte* ret = malloc(4 * sizeof(byte));
    unsigned int asInt = *((int*)&f);

    int i;
    for (i = 0; i < 4; i++) {
        ret[i] = (asInt >> 8 * i) & 0xFF;
    }

    return ret;
}

Vous pouvez le voir en action ici: http://ideone.com/umY1bB

Le problème avec les réponses ci-dessus est qu'elles s'appuient sur la représentation sous-jacente de floats: C ne garantit pas que l'octet le plus significatif sera "le premier" en mémoire. La norme permet au système sous-jacent d'implémenter floats comme vous le souhaitez - donc si vous testez votre code sur un système avec un type particulier d'endianness (ordre d'octet pour les types numériques en mémoire), il ne fonctionnera plus en fonction du type du processeur que vous exécutez sur

C'est un bug vraiment méchant, difficile à résoudre et que vous devriez éviter si possible. 

7
Patrick Collins

Je recommanderais d'essayer une "union".

Regardez ce post:

http://forum.arduino.cc/index.php?topic=158911.0

typedef union I2C_Packet_t{
 sensorData_t sensor;
 byte I2CPacket[sizeof(sensorData_t)];
};

Dans votre cas, quelque chose comme:

union {
  float float_variable;
  char bytes_array[4];
} my_union;

my_union.float_variable = 1.11;
5
FoggyDay

Encore une autre manière, sans union: (En supposant que byte = caractère non signé)

void floatToByte(byte* bytes, float f){

  int length = sizeof(float);

  for(int i = 0; i < length; i++){
    bytes[i] = ((byte*)&f)[i];
  }

}
3

Bien que les autres réponses montrent comment accomplir cela en utilisant une union, vous pouvez l'utiliser pour implémenter la fonction de votre choix:

byte[] float2Bytes(float val)
{
    my_union *u = malloc(sizeof(my_union));
    u->float_variable = val;
    return u->bytes_array;
}

ou

void float2Bytes(byte* bytes_array, float val)
{
    my_union u;
    u.float_variable = val;
    memcpy(bytes_array, u.bytes_array, 4);
}
2
mclaassen

cela semble fonctionner aussi

#include <stddef.h>
#include <stdint.h>
#include <string.h>

float fval = 1.11;
size_t siz;
siz = sizeof(float);

uint8_t ures[siz];

memcpy (&ures, &fval, siz);

puis

float utof;
memcpy (&utof, &ures, siz);

aussi pour double

double dval = 1.11;
siz = sizeof(double);

uint8_t ures[siz];

memcpy (&ures, &dval, siz);

puis

double utod;
memcpy (&utod, &ures, siz);
1
Enzo Guerra