0

how do I convert float to the unsigned char * array and print it using C++? I have the function below and I am getting the values -0.000000 when I try to print it.

Edited: I have a generic interface that has a function which returns unsigned char *. Each class that implements this function deal with different types of data, i.e.: strings, float, double, int, char. In the end I want all to return unsigned char *, not only char * because I care about what each function will transform to an array of byte.

unsigned char * readRequest() {
    float preCent = distanceCentimeters();

    std::cout << "readRequest" << std::endl;
    printf("%.10f ", preCent); // print correct result

    unsigned char buf[4];
    memcpy(buf, &preCent, sizeof(preCent));

    printf(" %s ", buf); // print bytes
    printf(" %lf ", buf); // prints -0.000000
    std::cout << buf << std::endl; // print bytes
    std::cout << "readRequest" << std::endl;
    return buf;
}

unsigned char *readRequestArray;
readRequestArray = (unsigned char*) readRequest();
std::cout << readRequestArray << std::endl; // prints (null)
Felipe
  • 7,013
  • 8
  • 44
  • 102
  • What is the `unsigned char` array supposed to be used for? Also note that `printf(" %lf ", buf);` invokes *undefined behavior* – UnholySheep Oct 09 '18 at 12:19
  • Do you want to print the byte representation of a float? – teroi Oct 09 '18 at 12:20
  • 2
    Also your function returns a pointer to an array that goes out of scope (hence it is a dangling pointer) – UnholySheep Oct 09 '18 at 12:21
  • 2
    when you ask something like "how do I convert a banana into an apple?" you have to explain what that conversion is supposed to mean, ie what do you exect the char array to hold after the conversion? – 463035818_is_not_an_ai Oct 09 '18 at 12:22
  • Appart from mixing printf-s with std::cout, i fail to see why this is tagged as c++ only. – babu646 Oct 09 '18 at 12:25
  • 3
    @IanA.B.K.: Presumably it is tagged C++ because the OP wants to know how to do it in C++, as asked in the first sentence of their question. Why shouldn’t the question be tagged C++? Do you think it has to be a question about classes or templates to be tagged C++? The answer for C would be different (as examining the bytes may be done through a union in C but not C++), so tagging C++ when C++ information is desired is appropriate. – Eric Postpischil Oct 09 '18 at 12:32
  • @user463035818 *Both* `printf` calls invoke undefined behaviour. So does the `memcpy` call, for that matter (technically, implementation defined behaviour). – Konrad Rudolph Oct 09 '18 at 12:34
  • @KonradRudolph not sure why you adress this comment at me. I was refering to different possiblities to get a char array from a float (digits to characters or getting the byte-wise representation, just to mention the two most obvious) – 463035818_is_not_an_ai Oct 09 '18 at 12:58
  • @user463035818 I tagged in the wrong user (autocomplete…). I meant UnholySheep. – Konrad Rudolph Oct 09 '18 at 12:59
  • @KonradRudolph no problem. Have to think of a more unique nickname ;) – 463035818_is_not_an_ai Oct 09 '18 at 13:00

2 Answers2

2

how do I convert float to the unsigned char * array

Depends on what you want to achieve by such conversion.

  • If you want to convert it into a textual representation, then you can use a string stream.
  • If you want to convert it to a sequence of bytes, then you can use std::memcpy to copy those bytes onto an array of unsigned char (you might alternatively use std::byte):

Example:

unsigned char buf[sizeof preCent];
std::memcpy(buf, &preCent, sizeof preCent);

... and print it

  • If you want the textual representation, simply insert the string into the standard output (std::cout)
  • If you want to see the byte sequence, you cannot let the stream interpret the byte array as a character encoded string, since binary data is not meaningful in that representation. You can iterate the bytes and show the numeric value of each byte:

Example:

for(unsigned char c : buf)
    std::cout << std::hex << (int)c;

Note the conversion to a non-character integer type to prevent the stream from interpreting the byte as an encoded character.


How [to] print the real float value

I want to print the float value after I convert it to unsigned char *

Simply convert the byte array back into a float using std::memcpy in reverse direction:

float converted_back;
std::memcpy(&converted_back, buf, sizeof converted_back);
std::cout << converted_back;

printf(" %lf ", buf); // prints -0.000000

The %lf requires that the argument is of type double (or float which will be converted into double). However, you passed buf which is of type unsigned char[4]. The behaviour of your program is undefined because you violate this precondition.

printf(" %s ", buf); // print bytes

%s specifier requires that the argument is a null terminated string. Your character array is not null terminated. The behaviour of your program is undefined because you violate this precondition. Besides, the data of your array is meaningless in character encoded representation.

std::cout << buf << std::endl; // print bytes

Character streams have the same requirements for inserted pointers as %s printf specifier does. The behaviour is undefined.

unsigned char buf[4];
...
return buf;

You return a pointer to a local array. The array is destroyed at the end of the function, and the returned pointer is dangling.

std::cout << readRequestArray << std::endl;

You insert a dangling pointer into a character stream. The behaviour of your program is undefined. Even if it wasn't dangling, the array it used to point to (the local buf) is still not a null terminated string.

Community
  • 1
  • 1
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • How do I do to your code `for(unsigned char c : buf) std::cout << std::hex << (int)c;` prints the real float value, not the hexadecimal? Now it is printing `6a4ec241` – Felipe Oct 09 '18 at 12:57
  • @FelipeOliveiraGutierrez you can use `std::cout << preCent;` to print the float value. – eerorika Oct 09 '18 at 12:58
  • yes. I know it. But I want to print the float value after I convert it to `unsigned char *` on `readRequestArray = (unsigned char*) readRequest();` line. – Felipe Oct 09 '18 at 13:38
  • I got a `Segmentation fault` and I described it in another question https://stackoverflow.com/questions/52723208/how-to-implement-a-function-returning-unsigned-char-and-print-it with your solution – Felipe Oct 09 '18 at 14:16
  • @FelipeOliveiraGutierrez I've already explained that in my answer: You return a pointer to a local array. The array is destroyed at the end of the function, and the returned pointer is dangling. You `std::memcpy` from the dangling pointer. The behaviour of your program is undefined. – eerorika Oct 09 '18 at 14:17
2

Printing with %s won't work because it expects a char * pointing to a null terminated string, while you have a char * pointer to an array of bytes. Using %lf also won't work because it expects a double, and a char * is incompatible with that. Both of these invoked undefined behavior.

If you want to print the byte representation which you have stored in buf, you need to print the value of each character individually.

unsigned char buf[sizeof(preCent)];
memcpy(buf, &preCent, sizeof(preCent));

for (size_t i=0; i<sizeof(preCent); i++) {
    printf("%02x ", buf[i]);
}
printf("\n");
dbush
  • 205,898
  • 23
  • 218
  • 273