web-dev-qa-db-ja.com

floatからバイト配列に変換するC関数

Float変数を受け入れ、それをバイト配列に変換する関数を作成しようとしています。動作するコードのスニペットを見つけましたが、可能であればそれを関数で再利用したいと思います。

私もArduino環境で作業していますが、ほとんどのC言語を受け入れることを理解しています。

現在動作しています:

float_variable = 1.11;
byte bytes_array[4];

*((float *)bytes_array) = float_variable;

この機能を動作させるためにここで何を変更できますか?

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;  
}

私はポインタなどにそれほど詳しくありませんが、(float)はキャストなどを使用していると読みましたか?

どんな助けも大歓迎です!

乾杯

*編集:解決済み

これを見つけた人のためにArduinoで動作する私の最後の機能は次のとおりです。以下の回答にはより効率的なソリューションがありますが、これは理解しても大丈夫だと思います。

関数:入力float変数をバイト配列に変換します

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);
}

関数を呼び出す

float float_example = 1.11;
byte bytes[4];

float2Bytes(float_example,&bytes[0]);

皆様のご協力に感謝します。過去20分間でポインターと参照について多くのことを学びました、Cheers Stack Overflow!

19
Ben Winding

最も簡単なのは、結合を作成することです。

#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;
}

出力:

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

注-バイトオーダーについての保証はありません...それはマシンのアーキテクチャに依存します。

関数を機能させるには、次を実行します。

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);
}

または、実際にハックする場合:

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

注-どちらの場合でも、入力パラメーターとして指定された場所にデータをコピーするようにしてください。ローカル変数は返された後は存在しないため、これは重要です(ただし、staticを宣言することはできますが、悪い習慣を教えてはいけません。関数が再び呼び出されたら…)

22
Floris

これは、現在のシステムとは異なる endianness のシステムを使用している場合に壊れないようにする方法です。

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;
}

ここで実際に動作を確認できます: http://ideone.com/umY1bB

上記の答えの問題は、floatsの基礎となる表現に依存していることです。Cは、メモリ内の最上位バイトが「最初」であることを保証しません。標準では、基になるシステムでfloatsを実装できますが、特定の種類のエンディアン(メモリ内の数値型のバイト順)を使用してシステムでコードをテストすると、動作しなくなります実行しているプロセッサの種類によって異なります

それは本当に厄介で修正が難しいバグであり、可能な限り避けるべきです。

9
Patrick Collins

「ユニオン」を試すことをお勧めします。

この投稿を見てください:

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

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

あなたの場合、次のようなものです:

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

my_union.float_variable = 1.11;
5
FoggyDay

ユニオンなしのさらに別の方法:(byte = unsigned charと仮定)

void floatToByte(byte* bytes, float f){

  int length = sizeof(float);

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

}

他の答えは、ユニオンを使用してこれを達成する方法を示していますが、これを使用して、次のように必要な機能を実装できます。

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

または

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

これも動作するようです

#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);

それから

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

ダブルも

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

uint8_t ures[siz];

memcpy (&ures, &dval, siz);

それから

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