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

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

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

问题

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

我有一串结构化的数据字符串,我想将其解析为元组。对于每种不同的输入字符串“种类”,数据的类型和排列都可能不同,因此我想使用模板和scanf格式来避免管理各种变量和重复的代码

下面的代码 *应该* 接受一个元组,将其成员展开为参数,然后根据“sscanf”的结果更新这些成员。

```cpp
#include <tuple>
#include <cstdio>
#include <cassert>

int main()
{
    // 纯粹的 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);
    // 放入一个一元元组似乎可以工作
    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);
    // 放入一个元组
    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;
}

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

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


<details>
<summary>英文:</summary>

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.

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;
}


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.

This is in C++17, under GCC.


</details>


# 答案1
**得分**: 4

问题实际上是您的格式字符串错误,而且您可能会遇到未定义行为。 您应该使用`%04hX`。 请注意`h`,它表示`short`,而不是完整长度的整数。 您所有的格式字符串都需要类似地修改:

请参阅https://godbolt.org/z/38PEPW39a

<details>
<summary>英文:</summary>

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:

See https://godbolt.org/z/38PEPW39a

</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:

确定