将sscanf应用于元组,元组未完全更新。

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

std::apply-ing sscanf into a tuple, tuple not fully updating

问题

以下是您提供的内容的翻译部分:

  1. 我有一串结构化的数据字符串,我想将其解析为元组。对于每种不同的输入字符串“种类”,数据的类型和排列都可能不同,因此我想使用模板和scanf格式来避免管理各种变量和重复的代码
  2. 下面的代码 *应该* 接受一个元组,将其成员展开为参数,然后根据“sscanf”的结果更新这些成员。
  3. ```cpp
  4. #include <tuple>
  5. #include <cstdio>
  6. #include <cassert>
  7. int main()
  8. {
  9. // 纯粹的 sscanf
  10. const char msg[] = "000000000A200890";
  11. const char fmt[] = "%04X%04X%04X%04X";
  12. uint16_t a, b, c, d;
  13. sscanf(msg, fmt, &a, &b, &c, &d);
  14. assert(a == 0x0000);
  15. assert(b == 0x0000);
  16. assert(c == 0x0A20);
  17. assert(d == 0x0890);
  18. // 放入一个一元元组似乎可以工作
  19. std::tuple<uint16_t> onetuple;
  20. const char *shortmsg = "10";
  21. const char *shortfmt = "%02X";
  22. std::apply([&shortmsg, &shortfmt](auto &...args) {
  23. sscanf(shortmsg, shortfmt, &args...);
  24. }, onetuple);
  25. assert(std::get<0>(onetuple) == 0x10);
  26. // 放入一个元组
  27. std::tuple<uint16_t, uint16_t, uint16_t, uint16_t> dest;
  28. std::apply([&msg, &fmt](auto &...args) {
  29. sscanf(msg, fmt, &args...);
  30. }, dest);
  31. assert(std.get<0>(dest) == 0x0000);
  32. assert(std.get<1>(dest) == 0x0000);
  33. assert(std.get<2>(dest) == 0x0A20);
  34. assert(std.get<3>(dest) == 0x0890);
  35. return 0;
  36. }

这个示例不起作用。第一部分使用纯粹的 sscanf 是正常的,表现如预期。最后一部分,我尝试将其“apply”到一个元组中 不会改变元组。但如果元组是一个一元元组(只有在这种情况下),代码就可以正常工作。

这是在C++17下,使用GCC。

  1. <details>
  2. <summary>英文:</summary>
  3. I have a structured string of data, and I want to parse it into a tuple. For each different *kind* of input string, the types and arrangement of the data can be different, so I want to use templates and scanf formats to avoid having to manage all sorts of variables and repetitive code.
  4. The code below *should* take a tuple, explode its members out as parameters, and then update those members based on the results of `sscanf`.

#include <tuple>
#include <cstdio>
#include <cassert>

int main()
{
//pure sscanf
const char msg[] = "000000000A200890";
const char fmt[] = "%04X%04X%04X%04X";
uint16_t a, b, c, d;
sscanf(msg, fmt, &a, &b, &c, &d);
assert(a == 0x0000);
assert(b == 0x0000);
assert(c == 0x0A20);
assert(d == 0x0890);
//into a one-tuple seems to work
std::tuple<uint16_t> onetuple;
const char *shortmsg = "10";
const char *shortfmt = "%02X";
std::apply([&shortmsg, &shortfmt](auto &...args) {
sscanf(shortmsg, shortfmt, &args...);
}, onetuple);
assert(std::get<0>(onetuple) == 0x10);
//into a tuple
std::tuple<uint16_t, uint16_t, uint16_t, uint16_t> dest;
std::apply([&msg, &fmt](auto &...args) {
sscanf(msg, fmt, &args...);
}, dest);
assert(std::get<0>(dest) == 0x0000);
assert(std::get<1>(dest) == 0x0000);
assert(std::get<2>(dest) == 0x0A20);
assert(std::get<3>(dest) == 0x0890);
return 0;
}

  1. This example doesn&#39;t work. The first block, using pure `sscanf` is fine, and behaves as expected. The last block, where I attempt to `apply` into a tuple *doesn&#39;t alter the tuple at all*. But if the tuple is a one-tuple (and only if it&#39;s a one-tuple), the code works fine.
  2. This is in C++17, under GCC.
  3. </details>
  4. # 答案1
  5. **得分**: 4
  6. 问题实际上是您的格式字符串错误,而且您可能会遇到未定义行为。 您应该使用`%04hX` 请注意`h`,它表示`short`,而不是完整长度的整数。 您所有的格式字符串都需要类似地修改:
  7. 请参阅https://godbolt.org/z/38PEPW39a
  8. <details>
  9. <summary>英文:</summary>
  10. Actually, the problem is that your format string is wrong, and you&#39;re probably hitting undefined behavior. You should be using `%04hX`. Note the `h` which indicates a `short`, as opposed to the full length integer. All of your format strings need to be similarly modified:
  11. See https://godbolt.org/z/38PEPW39a
  12. </details>

huangapple
  • 本文由 发表于 2023年2月24日 03:24:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/75549437.html
匿名

发表评论

匿名网友

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

确定