将结构体转换为字节,再将其转回结构体

25
我目前正在使用Arduino Uno、9DOF和XBee进行工作,我试图创建一个结构体,可以将其逐字节发送到串行端口,然后重新构建为结构体。
到目前为止,我有以下代码:
struct AMG_ANGLES {
    float yaw;
    float pitch;
    float roll;
};

int main() {
    AMG_ANGLES struct_data;

    struct_data.yaw = 87.96;
    struct_data.pitch = -114.58;
    struct_data.roll = 100.50;

    char* data = new char[sizeof(struct_data)];

    for(unsigned int i = 0; i<sizeof(struct_data); i++){
        // cout << (char*)(&struct_data+i) << endl;
        data[i] = (char*)(&struct_data+i); //Store the bytes of the struct to an array.
    }

    AMG_ANGLES* tmp = (AMG_ANGLES*)data; //Re-make the struct
    cout << tmp.yaw; //Display the yaw to see if it's correct.
}

来源: http://codepad.org/xMgxGY9Q

这段代码似乎无法运行,我不确定我做错了什么。

我该如何解决?


4
呼吁所有C++程序员使用C++风格的转换而非C风格的转换。 - Tobias Langner
3
没想到它们是C风格的转换,因为这是我的C++课堂老师教给我的。 - Steven10172
4个回答

40

看起来我用以下代码解决了我的问题。

struct AMG_ANGLES {
    float yaw;
    float pitch;
    float roll;
};

int main() {
    AMG_ANGLES struct_data;

    struct_data.yaw = 87.96;
    struct_data.pitch = -114.58;
    struct_data.roll = 100.50;

    //Sending Side
    char b[sizeof(struct_data)];
    memcpy(b, &struct_data, sizeof(struct_data));

    //Receiving Side
    AMG_ANGLES tmp; //Re-make the struct
    memcpy(&tmp, b, sizeof(tmp));
    cout << tmp.yaw; //Display the yaw to see if it's correct
}

警告:只有在发送和接收使用相同的字节序架构时,此代码才能正常工作。


2
除了你的警告之外,两边也需要完全相同地表示浮点数。我建议将其作为固定点整数发送(在你上面的示例中:8796、-11458、10050),并记录值的字节序。使用像endian.h中的htobe32()函数在主机和大端或小端之间进行转换。 - tomlogic
3
结构体可能存在填充,这将导致结构体无法紧密打包。 - Trevor Hickey

7
您的操作顺序错误,表达式如下:
&struct_data+i

struct_data的地址增加i倍结构体大小。请尝试以下方式:
*((char *) &struct_data + i)

这将struct_data的地址转换为char *,然后添加索引,再使用反引用运算符(一元*)获取该地址处的"char"。

它似乎不让我调用它。我得到了“第23行:错误:请求在'tmp'中的成员'yaw',它是非类类型'AMG_ANGLES *'”。 - Steven10172
看我的答案。你必须使用 '->'。 - jtepe
这对现在非常有帮助,六年后还是如此。谢谢您的好意先生! - Valdrinium

4
始终充分利用数据结构...
union AMG_ANGLES {
  struct {
    float yaw;
    float pitch;
    float roll;
  }data;
  char  size8[3*8];
  int   size32[3*4];
  float size64[3*1];
};

为什么浮点数是8个字节长? - Alin I
它不是浮点数。float是32位的。但是有double,基本上只是一个64位的浮点数。还有long double。 - Simon Nitzsche

1
for(unsigned int i = 0; i<sizeof(struct_data); i++){
    // +i has to be outside of the parentheses in order to increment the address
    // by the size of a char. Otherwise you would increment by the size of
    // struct_data. You also have to dereference the whole thing, or you will
    // assign an address to data[i]
    data[i] = *((char*)(&struct_data) + i); 
}

AMG_ANGLES* tmp = (AMG_ANGLES*)data; //Re-Make the struct
//tmp is a pointer so you have to use -> which is shorthand for (*tmp).yaw
cout << tmp->yaw; 
}

你的解决方案还是我的更有效率?这个操作将会每秒运行大约30-50次。 - Steven10172
memcpy可能更有效率,所以我会选择你的解决方案。它还使代码更易于阅读。 - jtepe
谢谢您解释为什么我需要使用->。我对C ++仍然很新,只有2-3个月的学习时间,所有的*和&有时仍然让我感到困惑。 - Steven10172
指针是C和C++初学者必须克服的经典障碍。至于为什么memcpy更有效率,请看这个问题:https://dev59.com/uHM_5IYBdhLWcg3w1G2N - jtepe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接