How to convert char* to float* using union or memcpy?
Using memcpy and reinterpretcast:
#include <cstdio>
#include <string>
#include <cstring>
#include <cassert>
#include <cstddef>
void using_pointer(const char *s, size_t slen) {
const float *f = reinterpret_cast<const float*>(s);
for (size_t i = 0; i < slen/sizeof(float); ++i) {
printf("%zu = %f\n", i, f[i]);
}
}
void using_memcpy(const char* s, size_t slen) {
float* f = new float[slen/sizeof(float)];
memcpy(f, s, slen/sizeof(float)*sizeof(float));
for (size_t i = 0; i < slen/sizeof(float); ++i) {
printf("%zu = %f\n", i, f[i]);
}
delete f;
}
int main() {
static_assert(sizeof(float) == 4, "");
std::string stdstr(
"\x00\x00\x80\x3f" // float 1.0
"\x00\x00\x81\x3f" // just randomly changed 0x80 to 0x81
"\x00\x00\x82\x3f"
, 4 * 3);
printf("using_pointer:\n");
using_pointer(stdstr.c_str(), stdstr.size());
printf("using_memcpy:\n");
using_memcpy(stdstr.c_str(), stdstr.size());
std::string s2("abcdefghijklmnopqrstuvwx");
printf("Last:\n");
using_memcpy(s2.c_str(), s2.size());
return 0;
}
will output on machine that is used by http://www.onlinegdb.com :
using_pointer:
0 = 1.000000
1 = 1.007812
2 = 1.015625
using_memcpy:
0 = 1.000000
1 = 1.007812
2 = 1.015625
Last:
0 = 16777999408082104352768.000000
1 = 4371022013021616997400576.000000
2 = 1138400301458999111806091264.000000
3 = 296401655701622853703074578432.000000
4 = 77151445562813935304650187079680.000000
5 = 20076561220099179535696200212676608.000000
@edit: As @drescherjm pointed out in comments, using union to convert between char and float representation is impossible in C++ unless based on undefined behavior. In C++ unions are not used to change representation of bytes. Unions are used to store at most one of multiple objects. You can store char array or float array in an union, not both at a time and you can't (at least shouldn't) convert between float and char representation using an union in C++.
What is happening in your code?
// static_cast<char*> from string is forbidden in iso C++. It's better to use should use at least std::string.c_str()
// or use char char_data_[sizeof("abcdefghijklmnopqrstuvwx"]; memcpy(char_data_, "abcdefghijklmnopqrstuvwx", sizeof(char_data_));
char *char_data_ = static_cast<char *>("abcdefghijklmnopqrstuvwx");
// you are allocating strlen("abcdefghijklmnopqrstuvwx")/4 = 24/4 = 6 bytes of memory. That's memory for 1 and a half float numbers.
float *float_data_ = reinterpret_cast<float *>(malloc(strlen(char_data_)/sizeof(float)));
// this will print '24\n'
printf("%ld\n", strlen(char_data_));
// you are copying 6 bytes of data from char_data_ to float_data_
// now float_data_ contains "abcdef" without '\0'
memcpy(float_data_, reinterpret_cast<float *>(char_data_), strlen(char_data_)/sizeof(float));
// this will print 16777999408082104352768.000000 on the first loop, which is "abcd" in hex in ascii
// then this invokes undefined behaviour cause of out of bound access
// you are trying to access elements number 2, 3, 4, 5 while float_data_ points to only 6 bytes, which is 1,5 float numbers, so even float_data_[1] is out of bound and undefined behaviour
for ( auto n = 0 ; n < strlen(char_data_)/sizeof(float); n++) {
printf("%f\n", *(float_data_ + n));
}