C++ 使用union或memcpy将char*转换为float*

C++ 使用union或memcpy将char*转换为float*,c++,C++,我试图将字符流转换为float*,但不知何故无法得到正确的结果 char *char_data_ = static_cast<char *>("abcdefghijklmnopqrstuvwx"); float *float_data_ = reinterpret_cast<float *>(malloc(strlen(char_data_)/sizeof(float))); printf("%ld\n", strlen(char_data_)); memcpy(

我试图将字符流转换为float*,但不知何故无法得到正确的结果

char  *char_data_  = static_cast<char *>("abcdefghijklmnopqrstuvwx");
float *float_data_ = reinterpret_cast<float *>(malloc(strlen(char_data_)/sizeof(float)));

printf("%ld\n", strlen(char_data_));

memcpy(float_data_, reinterpret_cast<float *>(char_data_), strlen(char_data_)/sizeof(float));

for ( auto n = 0 ; n < strlen(char_data_)/sizeof(float); n++) {
    printf("%f\n", *(float_data_ + n));
}
使用union可以解决这个问题吗


我希望每个字符流有4个字节的块,并将其保存到浮点数组中。

如何使用union或memcpy将char*转换为浮点*

使用memcpy和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;
}
编辑:正如@ DrEchchJM在评论中指出的那样,除非在未定义的行为基础上,否则在C++中使用联合来转换字符和浮点表示是不可能的。在C++中,不使用联合来改变字节的表示。联合最多用于存储多个对象中的一个。您可以将char数组或浮点数组存储在一个联合中,而不是一次一个,并且不能(至少不应该)使用C++中的联合来在浮点和字符表示之间转换。p> 您的代码中发生了什么

// 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));
}              
在ISO C++中,禁止从字符串中提取代码> /STATICO.SCAST。最好至少使用std::string.c_str() //或者使用char-char-char-char-char-char-char-char-char-char-char-char-char-char-data-sizeof(“char-efghijklmnopqrstuvx”);memcpy(char-char-char-char-char-char-upqrstuvx”,sizeof(char-data)); char*char_data=静态_cast(“abcdefghijklmnopqrstuvxx”); //您正在分配strlen(“abcdefghijklmnopqrstuvxx”)/4=24/4=6字节的内存。这是用于1个半浮点数的内存。 float*float_data_uuu=重新解释(malloc(strlen(char_data_uu)/sizeof(float)); //这将打印“24\n” printf(“%ld\n”,strlen(字符数据)); //您正在将6字节的数据从char_data_uu复制到float_data_ //现在float_data_uu包含不带“\0”的“abcdef” memcpy(float_data_)、reinterpret_cast(char_data_)、strlen(char_data_)/sizeof(float); //这将在第一个循环上打印167779994080882104352768.000000,即ascii十六进制的“abcd” //然后,由于越界访问,这将调用未定义的行为 //您试图访问元素编号2、3、4、5,而float_data_uuu仅指向6个字节,即1,5个float number,因此即使是float_data_uuu1也超出了范围且未定义 对于(自动n=0;n@dbush-我正试图从字符流中提取每个字符的4个字节,并将其分配给一个浮点数组。我正试图从字符流中提取每个字符的4个字节,并将其分配给一个浮点数组。那么,我所期望的问题的一部分是完全错误的。你应该期望一些浮点数。A
浮点要求数据以IEEE-754单精度浮点格式排序。我从未见过IEEE-754格式的拉丁字母。“我试图从字符流中提取每个字符4个字节…”这根本不可行。你希望从“hijk”中获得什么浮点值@信息阻塞,因为您没有复制足够的字节。您需要
strlen(char\u data)
,而不是
strlen(char\u data)/sizeof(float)
。此外,一个真正的浮点数流可能包含值为0的字节,在这种情况下,使用字符串函数是没有用的。非常感谢!malloc是您正确识别的问题。让我看看联合,然后再回来。这两种方法不是都未定义行为吗?我知道联合在
中肯定是UB>c++
。我明白了。使用union是未定义的行为。为什么要使用memcpy UB?我确信在我的机器(!)下,字符串中存储的字节表示浮点,因此我可以转换表示,因为我知道底层字节表示浮点对象。“使用指针”版本会导致未定义的行为(严格的别名冲突)但是底层内存包含一个与float兼容的对象,所以它不是严格的别名冲突。我知道这个内存在我的机器上包含float对象,所以它不是严格的别名冲突。是吗?
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      
// 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));
}