You can do it like this:

char data[sizeof(float)];


float f = 0.6f;

memcpy(data, &f, sizeof f);    // send data


float g;

memcpy(&g, data, sizeof g);    // receive data

In order for this to work, both machines need to use the same floating point representations.


As was rightly pointed out in the comments, you don't necessarily need to do the extra memcpy; instead, you can treat f directly as an array of characters (of any signedness). You still have to do memcpy on the receiving side, though, since you may not treat an arbitrary array of characters as a float! Example:

unsigned char const * const p = (unsigned char const *)&f;
for (size_t i = 0; i != sizeof f; ++i)
{
    printf("Byte %zu is %02X\n", i, p[i]);
    send_over_network(p[i]);
}
Answer from Kerrek SB on Stack Overflow
Top answer
1 of 6
25

You can do it like this:

char data[sizeof(float)];


float f = 0.6f;

memcpy(data, &f, sizeof f);    // send data


float g;

memcpy(&g, data, sizeof g);    // receive data

In order for this to work, both machines need to use the same floating point representations.


As was rightly pointed out in the comments, you don't necessarily need to do the extra memcpy; instead, you can treat f directly as an array of characters (of any signedness). You still have to do memcpy on the receiving side, though, since you may not treat an arbitrary array of characters as a float! Example:

unsigned char const * const p = (unsigned char const *)&f;
for (size_t i = 0; i != sizeof f; ++i)
{
    printf("Byte %zu is %02X\n", i, p[i]);
    send_over_network(p[i]);
}
2 of 6
9

In standard C is guaranted that any type can be accessed as an array of bytes. A straight way to do this is, of course, by using unions:

 #include <stdio.h> 

 int main(void)
 {
    float x = 0x1.0p-3; /* 2^(-3) in hexa */

    union float_bytes {
       float val;
       unsigned char bytes[sizeof(float)];
    } data;

    data.val = x;
    for (int i = 0; i < sizeof(float); i++) 
          printf("Byte %d: %.2x\n", i, data.bytes[i]);

    data.val *= 2;   /* Doing something with the float value */
    x = data.val;    /* Retrieving the float value           */
    printf("%.4f\n", data.val);

    getchar();
 }

As you can see, it is not necessary at all to use memcpy or pointers...

The union approach is easy to understand, standard and fast.

EDIT.

I will explain why this approach is valid in C (C99).

  • [5.2.4.2.1(1)] A byte has CHAR_BIT bits (an integer constant >= 8, in almost cases is 8).
  • [6.2.6.1(3)] The unsigned char type uses all its bits to represent the value of the object, which is an nonnegative integer, in a pure binary representation. This means that there are not padding bits or bits used for any other extrange purpouse. (The same thing is not guaranted for signed char or char types).
  • [6.2.6.1(2)] Every non-bitfield type is represented in memory as a contiguous sequence of bytes.
  • [6.2.6.1(4)] (Cited) "Values stored in non-bit-field objects of any other object type consist of n × CHAR_BIT bits, where n is the size of an object of that type, in bytes. The value may be copied into an object of type unsigned char [n] (e.g., by memcpy); [...]"
  • [6.7.2.1(14)] A pointer to a structure object (in particular, unions), suitably converted, points to its initial member. (Thus, there is no padding bytes at the beginning of a union).
  • [6.5(7)] The content of an object can be accessed by a character type:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the object,
— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively,amember of a subaggregate or contained union), or
— a character type

More information:

A discussion in google groups
Type-punning

EDIT 2

Another detail of the standard C99:

  • [6.5.2.3(3) footnote 82] Type-punning is allowed:

If the member used to access the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called "type punning"). This might be a trap representation.

🌐
Microsoft Learn
learn.microsoft.com › en-us › cpp › c-language › type-float
Type float | Microsoft Learn
... Floating-point numbers use the IEEE (Institute of Electrical and Electronics Engineers) format. Single-precision values with float type have 4 bytes, consisting of a sign bit, an 8-bit excess-127 binary exponent, and a 23-bit mantissa.
Discussions

casting - C Function to Convert float to byte array - Stack Overflow
Thanks for everyone's help, I've learnt so much about pointers and referencing in the past 20 minutes, Cheers Stack Overflow! ... Worrying about the execution time of copying 4 bytes, while at the same time using software floating point of AVR doesn't make sense. More on stackoverflow.com
🌐 stackoverflow.com
string - Parse four bytes to floating-point in C - Stack Overflow
How do I take four received data bytes and assemble them into a floating-point number? Right now I have the bytes stored in an array, which would be, received_data[1] ... received_data[4]. I would... More on stackoverflow.com
🌐 stackoverflow.com
c - Size of a float variable and compilation - Stack Overflow
Learn more about Collectives ... Bring the best of human thought and AI automation together at your work. Explore Stack Internal ... Save this question. Show activity on this post. I'm struggling to understand the behavior of gcc in this. The size of a float is of 4 bytes for my architecture. More on stackoverflow.com
🌐 stackoverflow.com
floating point - Convert 2 bytes or 3 bytes to a float in C - Stack Overflow
I'm working with a low-level protocol that has a high data rate and therefore uses 2 or 3 bytes to represent a float depending on the range of the number, to make the system more efficient. I'm tr... More on stackoverflow.com
🌐 stackoverflow.com
Top answer
1 of 7
22

Excerpt from the C99 standard, normative annex F (The C++-standard does not explicitly mention this annex, though it includes all affected functions without change per reference. Also, the types have to match for compatibility.):

IEC 60559 floating-point arithmetic

F.1 Introduction

1 This annex specifies C language support for the IEC 60559 floating-point standard. The IEC 60559 floating-point standard is specifically Binary floating-point arithmetic for microprocessor systems, second edition (IEC 60559:1989), previously designated IEC 559:1989 and as IEEE Standard for Binary Floating-Point Arithmetic (ANSI/IEEE 754−1985). IEEE Standard for Radix-Independent Floating-Point Arithmetic (ANSI/IEEE 854−1987) generalizes the binary standard to remove dependencies on radix and word length. IEC 60559 generally refers to the floating-point standard, as in IEC 60559 operation, IEC 60559 format, etc. An implementation that defines __STDC_IEC_559__ shall conform to the specifications in this annex.356) Where a binding between the C language and IEC 60559 is indicated, the IEC 60559-specified behavior is adopted by reference, unless stated otherwise. Since negative and positive infinity are representable in IEC 60559 formats, all real numbers lie within the range of representable values.

So, include <math.h> (or in C++ maybe <cmath>), and test for __STDC_IEC_559__.

If the macro is defined, not only are the types better specified (float being 32bits and double being 64bits among others), but also the behavior of builtin operators and standard-functions is more specified.
Lack of the macro does not give any guarantees.

For x86 and x86_64 (amd64), you can rely on the types float and double being IEC-60559-conformant, though functions using them and operations on them might not be.

2 of 7
14

Does not say anything about the size.

3.9.1.8

There are three floating point types: float, double, and long double. The type double provides at least as much precision as float, and the type long double provides at least as much precision as double. The set of values of the type float is a subset of the set of values of the type double; the set of values of the type double is a subset of the set of values of the type long double. The value representation of floating-point types is implementation-defined. Integral and floating types are collectively called arithmetic types. Specializations of the standard template std::numeric_limits (18.3) shall specify the maximum and minimum values of each arithmetic type for an implementation.

🌐
Quora
quora.com › How-many-bytes-of-memory-are-allocated-to-store-one-float-value-in-C
How many bytes of memory are allocated to store one float value in C++? - Quora
Answer (1 of 4): The size of a float, double, or long double is implementation-defined. Use the sizeof operator on the type you’re interested in to find the number of bytes occupied by that data type. Floating-point constants default to type double, without any qualifiers. Never assume the size...
🌐
Cprogramming
cboard.cprogramming.com › c-programming › 137150-floats-bytes-back-again.html
Floats to bytes and back again
unsigned char *d = (unsigned int *)&member; This requires a diagnostic because you can't assign an unsigned int* to an unsigned char*. You want to cast to unsigned char*. But if you do that, you do not use shifting and masking. You already have bytes. An unsigned char is a byte. As I mentioned, you can point a uint32_t* (or whatever type is the right size) at the float and then use shifting and masking.
🌐
W3Schools
w3schools.com › c › c_data_types.php
C Data Types
Every variable in C has a data type, such as int, float, char, or double, with a matching format specifier.
🌐
Wikipedia
en.wikipedia.org › wiki › C_data_types
C data types - Wikipedia
2 weeks ago - Information about the actual ... and <float.h> header defines macros for floating-point types. The actual values depend on the implementation. CHAR_BIT – size of the char type in bits, commonly referred to as the size of a byte (at least 8 bits)...
Find elsewhere
Top answer
1 of 9
31

Easiest is to make a 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;
}

Output:

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

Note - there is no guarantee about the byte order… it depends on your machine architecture.

To get your function to work, do this:

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

Or to really hack it:

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

Note - in either case I make sure to copy the data to the location given as the input parameter. This is crucial, as local variables will not exist after you return (although you could declare them static, but let's not teach you bad habits. What if the function gets called again…)

2 of 9
14

Here's a way to do what you want that won't break if you're on a system with a different endianness from the one you're on now:

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

You can see it in action here: http://ideone.com/umY1bB

The issue with the above answers is that they rely on the underlying representation of floats: C makes no guarantee that the most significant byte will be "first" in memory. The standard allows the underlying system to implement floats however it feels like -- so if you test your code on a system with a particular kind of endianness (byte order for numeric types in memory), it will stop working depending on the kind of processor you're running it on.

That's a really nasty, hard-to-fix bug and you should avoid it if at all possible.

🌐
Vultr
docs.vultr.com › examples › find the size of int, float, double and char
C Program to Find the Size of int, float, double and char
September 27, 2024 - This code confirms that the size of a char is 1 byte, which is standard across all standard C compilers. Using the sizeof operator in C helps determine the amount of memory needed for storing data types such as int, float, double, and char. This knowledge is essential for effective memory ...
Top answer
1 of 5
2

1)

Does sizeof(variable) simply get the variable type and return sizeof(type), which in this case would explain the result ?

Except for variable-length arrays, sizeof doesn't evaluate its operand. So yes, all it cares is the type. So sizeof(someFloatNumb) is 4 which is equivalent to sizeof(float). This explains printf("%i\n", sizeof(someFloatNumb));.

2)

[..] But I can still store a 8 bytes real value in a float, and my compiler says nothing about it. Does/Can gcc grow the capacity of a type ? (managing multiple variables behind the curtains to allow us that sort of things)

No. Capacity doesn't grow. You simply misunderstood how floats are represented/stored. sizeof(float) being 4 doesn't mean it can't store more than 2^32 (assuming 1 byte == 8 bits). See Floating point representation. What the maximum value of a float can represent is defined by the constant FLT_MAX (see <float.h>). sizeof(someFloatNumb) simply yields how many bytes the object (someFloatNumb) takes up in memory which isn't necessarily equal to the range of values it can represent. This explains why printf("%f\n", someFloatNumb); prints the value as expected (and there's no automatic "capacity growth").

3)

printf("%i\n", sizeof(281474976710656));

This is slightly more involved. As said before in (1), sizeof only cares about the type here. But the type of 281474976710656 is not necessarily int. The C standard defines the type of integer constants according to the smallest type that can represent the value. See https://stackoverflow.com/a/42115024/1275169 for an explanation.

On my system 281474976710656 can't be represented in an int and it's stored in a long int which is likely to be case on your system as well. So what you see is essentially equivalent to sizeof(long).

There's no portable way to determine the type of integer constants. But since you are using gcc, you could use a little trick with typeof:

typeof(281474976710656) x;
printf("%s", x); /* deliberately using '%s' to generate warning from gcc. */

generates:

warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘long int’ [-Wformat=] printf("%s", x);


P.S: sizeof results a size_t for which the correct format specifier is %zu. So that's what you should be using in your 1st and 3rd printf statements.

2 of 5
2

This doesn't store "8 bytes" of data, that value gets converted to an integer by the compiler, then converted to a float for assignment:

float someFloatNumb = 0xFFFFFFFFFFFF; // 6 bytes of data

Since float can represent large values, this isn't a big deal, but you will lose a lot of precision if you're only using 32-bit floats. Notice there's a slight but important difference here:

float value = 281474976710656.000000;
int value   = 281474976710655;

This is because float becomes an approximation when it runs out of precision.

Capacities don't "grow" for standard C types. You'll have to use a "bignum" library for that.

🌐
Programiz
programiz.com › c-programming › c-data-types
C Data Types
The size of float (single precision float data type) is 4 bytes. And the size of double (double precision float data type) is 8 bytes. Keyword char is used for declaring character type variables. For example, ... The size of the character variable is 1 byte. void is an incomplete type.
🌐
Stack Overflow
stackoverflow.com › questions › 40103041 › convert-2-bytes-or-3-bytes-to-a-float-in-c
floating point - Convert 2 bytes or 3 bytes to a float in C - Stack Overflow
I set both t and ax to zero first in case there are random bytes hanging around. ... The documentation is not great. Firstly they define a Float as a 32-bit IEEE 754 floating-point number.
🌐
Linux Hint
linuxhint.com › size-of-float-and-double-c-and-cpp
How to Find the Size of float and double in C and C++? – Linux Hint
The size of the float data type is 4 bytes and the size of the double data type is 8 bytes in C/C++. For further details, read the article.
🌐
TutorialsPoint
tutorialspoint.com › cprogramming › c_data_types.htm
C - Data Types
The expressions sizeof(type) yields the storage size of the object or type in bytes. Given below is an example to get the size of various type on a machine using different constant defined in limits.h header file − · #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <float.h> int main(int argc, char** argv) { printf("CHAR_BIT : %d\n", CHAR_BIT); printf("CHAR_MAX : %d\n", CHAR_MAX); printf("CHAR_MIN : %d\n", CHAR_MIN); printf("INT_MAX : %d\n", INT_MAX); printf("INT_MIN : %d\n", INT_MIN); printf("LONG_MAX : %ld\n", (long) LONG_MAX); printf("LONG_MIN : %ld\n", (long) LONG_MIN
🌐
Medium
medium.com › @Dev_Frank › datatypes-in-c-int-char-float-def790690c42
DATATYPES IN C (int, char, float) | by Dev Frank | Medium
February 5, 2024 - Floating-point numbers are numbers that have a decimal point or are expressed in exponential (scientific) notation. Here are the key characteristics and considerations regarding the float data type: The size of a float variable is typically 4 bytes ...
🌐
BYJUS
byjus.com › gate › size-of-data-types-in-c
Size of Data Types in C
February 16, 2024 - char – these are single-byte in nature. The char data type can hold a single character in a local character set. float – these are single-precision types of floating-point.
🌐
Intellipaat
intellipaat.com › home › blog › data types in c: a comprehensive guide (with examples)
Data Types in C: A Comprehensive Guide (With Examples)
October 6, 2025 - The storage size of the float variable is 4 bytes, but the size may vary for different processors, the same as the ‘int’ data type. In C language, the float values are represented by the ‘%f’ format specifier.