将C++字节结构转换/解析为Go语言。

huangapple go评论105阅读模式
英文:

Converting / Parsing C++ byte struct to Go

问题

我正在使用Go语言读取一些数据包,其中字段是C++数据类型。我尝试解析数据,但读取到的是垃圾值。

以下是一个小例子 - 特定数据类型的数据规范在C++中如下所示:

  1. struct CarTelemetryData
  2. {
  3. uint16 m_speed;
  4. uint8 m_throttle;
  5. int8 m_steer;
  6. uint8 m_brake;
  7. uint8 m_clutch;
  8. int8 m_gear;
  9. uint16 m_engineRPM;
  10. uint8 m_drs;
  11. uint8 m_revLightsPercent;
  12. uint16 m_brakesTemperature[4];
  13. uint16 m_tyresSurfaceTemperature[4];
  14. uint16 m_tyresInnerTemperature[4];
  15. uint16 m_engineTemperature;
  16. float m_tyresPressure[4];
  17. };

以下是我在Go中定义的内容:

  1. type CarTelemetryData struct {
  2. Speed uint16
  3. Throttle uint8
  4. Steer int8
  5. Brake uint8
  6. Clutch uint8
  7. Gear int8
  8. EngineRPM uint16
  9. DRS uint8
  10. RevLightsPercent uint8
  11. BrakesTemperature [4]uint16
  12. TyresSurfaceTemperature [4]uint16
  13. TyresInnerTemperature [4]uint16
  14. EngineTemperature uint16
  15. TyresPressure [4]float32
  16. }

对于实际的解包,我正在进行以下操作:

  1. func decodePayload(dataStruct interface{}, payload []byte) {
  2. dataReader := bytes.NewReader(payload[:])
  3. binary.Read(dataReader, binary.LittleEndian, dataStruct)
  4. }
  5. payload := make([]byte, 2048)
  6. s.conn.ReadFromUDP(payload[:])
  7. telemetryData := &data.CarTelemetryData{}
  8. s.PacketsRcvd += 1
  9. decodePayload(telemetryData, payload)

我怀疑这是因为数据类型不匹配,在将字节读入Go数据类型时存在一些转换问题,而它们最初是作为C++打包的。我该如何处理这个问题?

注意:我无法控制发送的数据,这是由第三方服务发送的。

英文:

I am reading some data packets in Go, where the fields are C++ data types. I tried parsing the data but I am reading garbage values.

Here is a small example - the data spec sheet for a particular datatype is as follows in C++,

  1. struct CarTelemetryData
  2. {
  3. uint16 m_speed;
  4. uint8 m_throttle;
  5. int8 m_steer;
  6. uint8 m_brake;
  7. uint8 m_clutch;
  8. int8 m_gear;
  9. uint16 m_engineRPM;
  10. uint8 m_drs;
  11. uint8 m_revLightsPercent;
  12. uint16 m_brakesTemperature[4];
  13. uint16 m_tyresSurfaceTemperature[4];
  14. uint16 m_tyresInnerTemperature[4];
  15. uint16 m_engineTemperature;
  16. float m_tyresPressure[4];
  17. };

And below is what I have defined in Go

  1. type CarTelemetryData struct {
  2. Speed uint16
  3. Throttle uint8
  4. Steer int8
  5. Brake uint8
  6. Clutch uint8
  7. Gear int8
  8. EngineRPM uint16
  9. DRS uint8
  10. RevLightsPercent uint8
  11. BrakesTemperature [4]uint16
  12. TyresSurfaceTemperature [4]uint16
  13. TyresInnerTemperature [4]uint16
  14. EngineTemperature uint16
  15. TyresPressure [4]float32
  16. }

For the actual un-marshalling, I am doing this -

  1. func decodePayload(dataStruct interface{}, payload []byte) {
  2. dataReader := bytes.NewReader(payload[:])
  3. binary.Read(dataReader, binary.LittleEndian, dataStruct)
  4. }
  5. payload := make([]byte, 2048)
  6. s.conn.ReadFromUDP(payload[:])
  7. telemetryData := &data.CarTelemetryData{}
  8. s.PacketsRcvd += 1
  9. decodePayload(telemetryData, payload)

I suspect that this is because the datatypes are not equivalent and there is some conversion issue while reading the bytes into Go data-types, whereas they have been originally packages as C++. How can I deal with this?

Note: I don't have any control over the data that is sent, this is sent by a third party service.

答案1

得分: 2

你所面临的问题与结构成员的对齐有关。你可以在这里阅读更多相关信息,简而言之,C++编译器有时会添加填充字节,以保持体系结构所期望的自然对齐方式。如果不使用该对齐方式,可能会导致性能下降甚至访问冲突。

例如,在x86/x64上,大多数类型的对齐方式通常(但不一定保证)与其大小相同。我们可以看到:

  1. #include <cstdint>
  2. #include <type_traits>
  3. std::size_t offsets[] = {
  4. std::alignment_of_v<std::uint8_t>,
  5. std::alignment_of_v<std::uint16_t>,
  6. std::alignment_of_v<std::uint32_t>,
  7. std::alignment_of_v<std::uint64_t>,
  8. std::alignment_of_v<__uint128_t>,
  9. std::alignment_of_v<std::int8_t>,
  10. std::alignment_of_v<std::int16_t>,
  11. std::alignment_of_v<std::int32_t>,
  12. std::alignment_of_v<std::int64_t>,
  13. std::alignment_of_v<__int128_t>,
  14. std::alignment_of_v<float>,
  15. std::alignment_of_v<double>,
  16. std::alignment_of_v<long double>,
  17. std::alignment_of_v<void*>,
  18. };

编译为:

  1. offsets:
  2. .quad 1
  3. .quad 2
  4. .quad 4
  5. .quad 8
  6. .quad 16
  7. .quad 1
  8. .quad 2
  9. .quad 4
  10. .quad 8
  11. .quad 16
  12. .quad 4
  13. .quad 8
  14. .quad 16
  15. .quad 8

由于这些(和其他)实现细节,不建议依赖内部表示。然而,在某些情况下,其他方法可能不够快(例如逐个字段序列化),或者您可能无法更改C++代码,就像OP一样。

binary.Read期望紧凑的数据,但C++会使用填充。我们需要使用特定于编译器的指令,例如#pragma pack(1),或者在Go结构体中添加填充。第一种选项对于OP来说不可行,所以我们将使用第二种选项。

我们可以使用offsetof宏来确定结构成员相对于结构本身的偏移量。我们可以这样做:

  1. #include <array>
  2. #include <cstddef>
  3. #include <cstdint>
  4. using int8 = std::int8_t;
  5. using uint8 = std::uint8_t;
  6. using uint16 = std::uint16_t;
  7. struct CarTelemetryData {
  8. uint16 m_speed;
  9. uint8 m_throttle;
  10. int8 m_steer;
  11. uint8 m_brake;
  12. uint8 m_clutch;
  13. int8 m_gear;
  14. uint16 m_engineRPM;
  15. uint8 m_drs;
  16. uint8 m_revLightsPercent;
  17. uint16 m_brakesTemperature[4];
  18. uint16 m_tyresSurfaceTemperature[4];
  19. uint16 m_tyresInnerTemperature[4];
  20. uint16 m_engineTemperature;
  21. float m_tyresPressure[4];
  22. };
  23. // C++没有反射(尚未),所以我们需要列出每个成员
  24. constexpr auto offsets = std::array{
  25. offsetof(CarTelemetryData, m_speed),
  26. offsetof(CarTelemetryData, m_throttle),
  27. offsetof(CarTelemetryData, m_steer),
  28. offsetof(CarTelemetryData, m_brake),
  29. offsetof(CarTelemetryData, m_clutch),
  30. offsetof(CarTelemetryData, m_gear),
  31. offsetof(CarTelemetryData, m_engineRPM),
  32. offsetof(CarTelemetryData, m_drs),
  33. offsetof(CarTelemetryData, m_revLightsPercent),
  34. offsetof(CarTelemetryData, m_brakesTemperature),
  35. offsetof(CarTelemetryData, m_tyresSurfaceTemperature),
  36. offsetof(CarTelemetryData, m_tyresInnerTemperature),
  37. offsetof(CarTelemetryData, m_engineTemperature),
  38. offsetof(CarTelemetryData, m_tyresPressure),
  39. };
  40. constexpr auto sizes = std::array{
  41. sizeof(CarTelemetryData::m_speed),
  42. sizeof(CarTelemetryData::m_throttle),
  43. sizeof(CarTelemetryData::m_steer),
  44. sizeof(CarTelemetryData::m_brake),
  45. sizeof(CarTelemetryData::m_clutch),
  46. sizeof(CarTelemetryData::m_gear),
  47. sizeof(CarTelemetryData::m_engineRPM),
  48. sizeof(CarTelemetryData::m_drs),
  49. sizeof(CarTelemetryData::m_revLightsPercent),
  50. sizeof(CarTelemetryData::m_brakesTemperature),
  51. sizeof(CarTelemetryData::m_tyresSurfaceTemperature),
  52. sizeof(CarTelemetryData::m_tyresInnerTemperature),
  53. sizeof(CarTelemetryData::m_engineTemperature),
  54. sizeof(CarTelemetryData::m_tyresPressure),
  55. };
  56. constexpr auto computePadding() {
  57. std::array<std::size_t, offsets.size()> result;
  58. std::size_t expectedOffset = 0;
  59. for (std::size_t i = 0; i < offsets.size(); i++) {
  60. result.at(i) = offsets.at(i) - expectedOffset;
  61. expectedOffset = offsets.at(i) + sizes.at(i);
  62. }
  63. return result;
  64. }
  65. auto padding = computePadding();

它编译为(constexpr FTW)

  1. padding:
  2. .quad 0
  3. .quad 0
  4. .quad 0
  5. .quad 0
  6. .quad 0
  7. .quad 0
  8. .quad 1
  9. .quad 0
  10. .quad 0
  11. .quad 0
  12. .quad 0
  13. .quad 0
  14. .quad 0
  15. .quad 2

因此,在x86上,EngineRPM之前需要一个字节,在TyresPressure之前需要两个字节。

因此,让我们检查一下是否有效

C++:

  1. #include <cstddef>
  2. #include <cstdint>
  3. #include <iomanip>
  4. #include <iostream>
  5. #include <span>
  6. using int8 = std::int8_t;
  7. using uint8 = std::uint8_t;
  8. using uint16 = std::uint16_t;
  9. struct CarTelemetryData {
  10. uint16 m_speed;
  11. uint8 m_throttle;
  12. int8 m_steer;
  13. uint8 m_brake;
  14. uint8 m_clutch;
  15. int8 m_gear;
  16. uint16 m_engineRPM;
  17. uint8 m_drs;
  18. uint8 m_revLightsPercent;
  19. uint16 m_brakesTemperature[4];
  20. uint16 m_tyresSurfaceTemperature[4];
  21. uint16 m_tyresInnerTemperature[4];
  22. uint16 m_engineTemperature;
  23. float m_tyresPressure[4];
  24. };
  25. int main() {
  26. CarTelemetryData data = {
  27. .m_speed = 1,
  28. .m_throttle = 2,
  29. .m_steer = 3,
  30. .m_brake = 4,
  31. .m_clutch = 5,
  32. .m_gear = 6,
  33. .m_engineRPM = 7,
  34. .m_drs = 8,
  35. .m_revLightsPercent = 9,
  36. .m_brakesTemperature = {10, 11, 12, 13},
  37. .m_tyresSurfaceTemperature = {14, 15, 16, 17},
  38. .m_tyresInnerTemperature = {18, 19, 20, 21},
  39. .m_engineTemperature = 22,
  40. .m_tyresPressure = {23, 24, 25, 26},
  41. };
  42. std::cout << "b := []byte{" << std::hex << std::setfill('0');
  43. for (auto byte : std::as_bytes(std::span(&data, 1))) {
  44. std::cout << "0x" << std::setw(2) << static_cast<unsigned>(byte)
  45. << ", ";
  46. }
  47. std::cout << "}";
  48. }

结果为

  1. b := []byte{0x01, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x07, 0x00, 0x08, 0x09, 0x0a, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x41, 0x00, 0x00, 0xc0, 0x41, 0x00, 0x00, 0xc8, 0x41, 0x00, 0x00, 0xd0, 0x41, }

让我们在Go中使用它:

  1. // Type your code here, or load an example.
  2. // Your function name should start with a capital letter.
  3. package main
  4. import (
  5. "bytes"
  6. "encoding/binary"
  7. "fmt"
  8. )
  9. type CarTelemetryData struct {
  10. Speed uint16
  11. Throttle uint8
  12. Steer int8
  13. Brake uint8
  14. Clutch uint8
  15. Gear int8
  16. _ uint8
  17. EngineRPM uint16
  18. DRS uint8
  19. RevLightsPercent uint8
  20. BrakesTemperature [4]uint16
  21. TyresSurfaceTemperature [4]uint16
  22. TyresInnerTemperature [4]uint16
  23. EngineTemperature uint16
  24. _ uint16
  25. TyresPressure [4]float32
  26. }
  27. func main() {
  28. b := []byte{0x01, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x07, 0x00, 0x08, 0x09, 0x0a, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x41, 0x00, 0x00, 0xc0, 0x41, 0x00, 0x00, 0xc8, 0x41, 0x00, 0x00, 0xd0, 0x41}
  29. var dataStruct CarTelemetryData
  30. dataReader := bytes.NewReader(b[:])
  31. binary.Read(dataReader, binary.LittleEndian, &dataStruct)
  32. fmt.Printf("%+v", dataStruct)
  33. }

它打印出

  1. {Speed:1 Throttle:2 Steer:3 Brake:4 Clutch:5 Gear:6 _:0 EngineRPM:7 DRS:8 RevLightsPercent:9 BrakesTemperature:[10 11 12 13] TyresSurfaceTemperature:[14 15 16 17] TyresInnerTemperature:[18 19 20 21] EngineTemperature:22 _:0 TyresPressure:[23 24 25 26]}

如果去掉填充字节,它将失败。

英文:

The issue you're facing has to do with the alignment of struct members. You can read more about it here but, in short, the C++ compiler will sometimes add padding bytes in order to maintain the natural alignment expected by the architecture. If that alignment is not used, it may cause degraded performance or even an access violation.

For x86/x64, for example, the alignment of most types will usually (but not necessarily guaranteed to) be the same as the size. We can see that

  1. #include &lt;cstdint&gt;
  2. #include &lt;type_traits&gt;
  3. std::size_t offsets[] = {
  4. std::alignment_of_v&lt;std::uint8_t&gt;,
  5. std::alignment_of_v&lt;std::uint16_t&gt;,
  6. std::alignment_of_v&lt;std::uint32_t&gt;,
  7. std::alignment_of_v&lt;std::uint64_t&gt;,
  8. std::alignment_of_v&lt;__uint128_t&gt;,
  9. std::alignment_of_v&lt;std::int8_t&gt;,
  10. std::alignment_of_v&lt;std::int16_t&gt;,
  11. std::alignment_of_v&lt;std::int32_t&gt;,
  12. std::alignment_of_v&lt;std::int64_t&gt;,
  13. std::alignment_of_v&lt;__int128_t&gt;,
  14. std::alignment_of_v&lt;float&gt;,
  15. std::alignment_of_v&lt;double&gt;,
  16. std::alignment_of_v&lt;long double&gt;,
  17. std::alignment_of_v&lt;void*&gt;,
  18. };

compiles to

  1. offsets:
  2. .quad 1
  3. .quad 2
  4. .quad 4
  5. .quad 8
  6. .quad 16
  7. .quad 1
  8. .quad 2
  9. .quad 4
  10. .quad 8
  11. .quad 16
  12. .quad 4
  13. .quad 8
  14. .quad 16
  15. .quad 8

Due to these (and other) implementation details, it may be advisable to not rely on the internal representation. In some cases, however, other methods may not be fast enough (such as serializing field by field), or you may not be able to change the C++ code, like OP.

binary.Read expects packed data, but C++ will use padding. We need to either use a compiler-dependent directive such as #pragma pack(1) or add padding the Go struct. The first is not an option for OP, so we'll use the second.

We can use the offsetof macro to determine the offset of a struct member relative to the struct itself. We can do something like

  1. #include &lt;array&gt;
  2. #include &lt;cstddef&gt;
  3. #include &lt;cstdint&gt;
  4. using int8 = std::int8_t;
  5. using uint8 = std::uint8_t;
  6. using uint16 = std::uint16_t;
  7. struct CarTelemetryData {
  8. uint16 m_speed;
  9. uint8 m_throttle;
  10. int8 m_steer;
  11. uint8 m_brake;
  12. uint8 m_clutch;
  13. int8 m_gear;
  14. uint16 m_engineRPM;
  15. uint8 m_drs;
  16. uint8 m_revLightsPercent;
  17. uint16 m_brakesTemperature[4];
  18. uint16 m_tyresSurfaceTemperature[4];
  19. uint16 m_tyresInnerTemperature[4];
  20. uint16 m_engineTemperature;
  21. float m_tyresPressure[4];
  22. };
  23. // C++ has no reflection (yet) so we need to list every member
  24. constexpr auto offsets = std::array{
  25. offsetof(CarTelemetryData, m_speed),
  26. offsetof(CarTelemetryData, m_throttle),
  27. offsetof(CarTelemetryData, m_steer),
  28. offsetof(CarTelemetryData, m_brake),
  29. offsetof(CarTelemetryData, m_clutch),
  30. offsetof(CarTelemetryData, m_gear),
  31. offsetof(CarTelemetryData, m_engineRPM),
  32. offsetof(CarTelemetryData, m_drs),
  33. offsetof(CarTelemetryData, m_revLightsPercent),
  34. offsetof(CarTelemetryData, m_brakesTemperature),
  35. offsetof(CarTelemetryData, m_tyresSurfaceTemperature),
  36. offsetof(CarTelemetryData, m_tyresInnerTemperature),
  37. offsetof(CarTelemetryData, m_engineTemperature),
  38. offsetof(CarTelemetryData, m_tyresPressure),
  39. };
  40. constexpr auto sizes = std::array{
  41. sizeof(CarTelemetryData::m_speed),
  42. sizeof(CarTelemetryData::m_throttle),
  43. sizeof(CarTelemetryData::m_steer),
  44. sizeof(CarTelemetryData::m_brake),
  45. sizeof(CarTelemetryData::m_clutch),
  46. sizeof(CarTelemetryData::m_gear),
  47. sizeof(CarTelemetryData::m_engineRPM),
  48. sizeof(CarTelemetryData::m_drs),
  49. sizeof(CarTelemetryData::m_revLightsPercent),
  50. sizeof(CarTelemetryData::m_brakesTemperature),
  51. sizeof(CarTelemetryData::m_tyresSurfaceTemperature),
  52. sizeof(CarTelemetryData::m_tyresInnerTemperature),
  53. sizeof(CarTelemetryData::m_engineTemperature),
  54. sizeof(CarTelemetryData::m_tyresPressure),
  55. };
  56. constexpr auto computePadding() {
  57. std::array&lt;std::size_t, offsets.size()&gt; result;
  58. std::size_t expectedOffset = 0;
  59. for (std::size_t i = 0; i &lt; offsets.size(); i++) {
  60. result.at(i) = offsets.at(i) - expectedOffset;
  61. expectedOffset = offsets.at(i) + sizes.at(i);
  62. }
  63. return result;
  64. }
  65. auto padding = computePadding();

which compiles to (constexpr FTW)

  1. padding:
  2. .quad 0
  3. .quad 0
  4. .quad 0
  5. .quad 0
  6. .quad 0
  7. .quad 0
  8. .quad 1
  9. .quad 0
  10. .quad 0
  11. .quad 0
  12. .quad 0
  13. .quad 0
  14. .quad 0
  15. .quad 2

So, on x86, we need one byte before EngineRPM and two bytes before TyresPressure.

So, let's check if that works.

C++:

  1. #include &lt;cstddef&gt;
  2. #include &lt;cstdint&gt;
  3. #include &lt;iomanip&gt;
  4. #include &lt;iostream&gt;
  5. #include &lt;span&gt;
  6. using int8 = std::int8_t;
  7. using uint8 = std::uint8_t;
  8. using uint16 = std::uint16_t;
  9. struct CarTelemetryData {
  10. uint16 m_speed;
  11. uint8 m_throttle;
  12. int8 m_steer;
  13. uint8 m_brake;
  14. uint8 m_clutch;
  15. int8 m_gear;
  16. uint16 m_engineRPM;
  17. uint8 m_drs;
  18. uint8 m_revLightsPercent;
  19. uint16 m_brakesTemperature[4];
  20. uint16 m_tyresSurfaceTemperature[4];
  21. uint16 m_tyresInnerTemperature[4];
  22. uint16 m_engineTemperature;
  23. float m_tyresPressure[4];
  24. };
  25. int main() {
  26. CarTelemetryData data = {
  27. .m_speed = 1,
  28. .m_throttle = 2,
  29. .m_steer = 3,
  30. .m_brake = 4,
  31. .m_clutch = 5,
  32. .m_gear = 6,
  33. .m_engineRPM = 7,
  34. .m_drs = 8,
  35. .m_revLightsPercent = 9,
  36. .m_brakesTemperature = {10, 11, 12, 13},
  37. .m_tyresSurfaceTemperature = {14, 15, 16, 17},
  38. .m_tyresInnerTemperature = {18, 19, 20, 21},
  39. .m_engineTemperature = 22,
  40. .m_tyresPressure = {23, 24, 25, 26},
  41. };
  42. std::cout &lt;&lt; &quot;b := []byte{&quot; &lt;&lt; std::hex &lt;&lt; std::setfill(&#39;0&#39;);
  43. for (auto byte : std::as_bytes(std::span(&amp;data, 1))) {
  44. std::cout &lt;&lt; &quot;0x&quot; &lt;&lt; std::setw(2) &lt;&lt; static_cast&lt;unsigned&gt;(byte)
  45. &lt;&lt; &quot;, &quot;;
  46. }
  47. std::cout &lt;&lt; &quot;}&quot;;
  48. }

results in

  1. b := []byte{0x01, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x07, 0x00, 0x08, 0x09, 0x0a, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x41, 0x00, 0x00, 0xc0, 0x41, 0x00, 0x00, 0xc8, 0x41, 0x00, 0x00, 0xd0, 0x41, }

Let's use that in Go:

  1. // Type your code here, or load an example.
  2. // Your function name should start with a capital letter.
  3. package main
  4. import (
  5. &quot;bytes&quot;
  6. &quot;encoding/binary&quot;
  7. &quot;fmt&quot;
  8. )
  9. type CarTelemetryData struct {
  10. Speed uint16
  11. Throttle uint8
  12. Steer int8
  13. Brake uint8
  14. Clutch uint8
  15. Gear int8
  16. _ uint8
  17. EngineRPM uint16
  18. DRS uint8
  19. RevLightsPercent uint8
  20. BrakesTemperature [4]uint16
  21. TyresSurfaceTemperature [4]uint16
  22. TyresInnerTemperature [4]uint16
  23. EngineTemperature uint16
  24. _ uint16
  25. TyresPressure [4]float32
  26. }
  27. func main() {
  28. b := []byte{0x01, 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x07, 0x00, 0x08, 0x09, 0x0a, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x0d, 0x00, 0x0e, 0x00, 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x12, 0x00, 0x13, 0x00, 0x14, 0x00, 0x15, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x41, 0x00, 0x00, 0xc0, 0x41, 0x00, 0x00, 0xc8, 0x41, 0x00, 0x00, 0xd0, 0x41}
  29. var dataStruct CarTelemetryData
  30. dataReader := bytes.NewReader(b[:])
  31. binary.Read(dataReader, binary.LittleEndian, &amp;dataStruct)
  32. fmt.Printf(&quot;%+v&quot;, dataStruct)
  33. }

which prints

  1. {Speed:1 Throttle:2 Steer:3 Brake:4 Clutch:5 Gear:6 _:0 EngineRPM:7 DRS:8 RevLightsPercent:9 BrakesTemperature:[10 11 12 13] TyresSurfaceTemperature:[14 15 16 17] TyresInnerTemperature:[18 19 20 21] EngineTemperature:22 _:0 TyresPressure:[23 24 25 26]}

Take the padding bytes out and it fails.

huangapple
  • 本文由 发表于 2022年2月20日 06:54:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/71189898.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定