如何将多个字符读取组合成std::vector?

3
我正在从一个HID设备读取多个报告到一个unsigned char中,然后尝试将数据复制到std :: vector中。我还将数据写入文件进行十六进制分析,当我查看时,其内容似乎是正确的。但是,当我将其转储到控制台时,std :: vector似乎不包含正确的数据。
这是代码:
typedef vector<unsigned char> buffer_t;

buffer_t sendCommand (hid_device *devh, const unsigned char cmd[], int reports) {
    unsigned char outbuf[0x40];
    buffer_t retbuf(0x40 * reports);

    hid_write(devh, cmd, 0x41);

    int i;
    FILE *file = fopen("test.out", "w+b");
    while (i++ < reports) {
       hid_read(devh, outbuf, 0x40);
       fwrite(outbuf, 1, sizeof(outbuf), file);
       retbuf.push_back(*outbuf);
    }
    fclose(file);
    cout << &retbuf[0];
    return retbuf;
}

我有一种感觉,我可能完全错了;我对C/C++相当新,并且我已经陷入了这个问题中一段时间。有人能告诉我我做错了什么,或者指引我更好的方向吗?


你的向量将只包含outbuf的第一个字符,因为你正在使用*outbuf。 - jsist
5个回答

6

您想向向矢量添加多个unsigned char对象,但push_back只添加一个。

因此,请将retbuf.push_back(* outbuf);替换为以下内容之一:

for (size_t i = 0; i < sizeof(outbuf); ++i) {
    retbuf.push_back(outbuf[i]);
}

或者

std::copy(outbuf, outbuf+sizeof(outbuf), std::back_inserter(retbuf));

或者

retbuf.insert(retbuf.end(), outbuf, outbuf+sizeof(outbuf));

这些都是做同样的事情。

您可以使用特定大小创建您的向量:

buffer_t retbuf(0x40 * reports);

但是push_back通过在末尾添加一个元素来增加向量的大小。您应该将其创建为空:

buffer_t retbuf;

如果需要,您可以为向量分配足够的空间,以准备添加元素:

retbuf.reserve(0x40 * reports);

这只是一个性能问题,但有时对于大向量或类型向量(与unsigned char不同)在向量用完内部空间并需要分配更多空间时,复制/移动成本很高。

关于风格的说明:您重复几次文字值0x40,还使用sizeof(outbuf)。通常最好定义一个常量,并在整个过程中使用该名称:

const int report_size = 0x40;

这样做部分是为了以后数字更改的情况,但它也与您的代码易读性有关 - 如果有人看到0x40,他们可能不会立即理解为什么这是正确的值。如果有人看到report_size,则在查找该值之前并不知道该值实际上是多少,但是他们确实知道您使用该值的原因。


感谢您详细的回答。我已经尝试了您提供的每个解决方案,您说得对,它们都可以实现相同的功能。然而,当我使用cout << &rebuf[0]sizeof()为8,而不是0x40 * reports)时,控制台输出仍然不正确。这可能与HID报告的结构有关吗?它们可以很好地写入文件... - Andy E
请原谅我的无知,这就是我看到的。我以为它会倾泻出所有东西,但现在我明白为什么它不会了...那我该如何倾泻出所有东西呢?我打算将内存复制到一个结构体中,这样我就可以从报告中获取所需的部分了。 - Andy E
&retbuf[0] 是指向向量中第一个 unsigned char 的指针。它的类型是 unsigned char*,当你使用 cout<< 时,地址会被打印出来。很抱歉我之前删除的评论是错误的,因为我错过了 &。要转储整个向量,请执行以下操作:根据数据是人类可读的(因此将其作为字符打印)还是二进制(因此将其作为数字打印),执行 std::copy(retval.begin(), retval.end(), ostream_iterator<unsigned char>(cout)); 或者 std::copy(retval.begin(), retval.end(), ostream_iterator<int>(cout, " ")); - Steve Jessop
哦,如果你计划将内存复制到一个结构体中,那么最好一开始就使用vector<my_report_struct>而不是vector<unsigned char> - Steve Jessop
糟糕,我又出错了——operator<<(const unsigned char*)不会打印地址,它的行为类似于char*重载,需要一个以空字符结尾的C风格字符串。因此,它可能会打印向量中部分数据然后停止,或者如果向量中没有终止字节,则可能会打印整个向量内容然后越界,导致未定义的行为。 - Steve Jessop
谢谢,我会继续尝试并看看我能做什么。这都是学习过程的一部分,我想。 - Andy E

1
使用std::vector的assign函数可以推回多个值。例如:
std::vector<char>vec1;
char array[3] = {'a', 'b', 'c'};
vec1.assign(array, array+3);

我目前正在一个需要这样做的项目上工作。


1
问题出在这一行:buffer_t retbuf(0x40 * reports); 这意味着你创建了一个向量,其中包含0x40 * reports个元素,这些元素填充了无符号字符的默认值(零)。然后push_back()只是将新元素添加到向量的末尾,不会影响现有元素。

你需要这样重写它:

buffer_t retbuf;                  // Empty vector
retbuf.reserve(0x40 * reports);   // Preallocate memory for known element count

这样push_back()将按预期工作,并从开头向空向量添加元素。

当然,您应该push_back() outbuf的所有元素,而不仅仅是第一个(*outbuf)。


0
请注意,由于outbuf是一个char数组,因此*outbuf将成为char数组的第一个元素,因为数组/指针具有二义性。
我认为你可能想要执行以下操作:
typedef vector<string> buffer_t; // alternatively vector<unsigned char*>
...
retbuf.push_back(outbuf);
...

或者

typedef vector<unsigned char> buffer_t;
...
for (size_t i = 0; i < sizeof(outbuf); i++)
     retbuf.push_back(outbuf);
...

0
你的向量是一种名为unsigned char的类型,这意味着它的每个元素都是这种类型。你的outbuf是一个无符号字符数组。 push_back()函数只会将一个项目附加到向量的末尾,因此push_back(*outbuf)仅会将outbuf的第一个元素添加到向量中,而不是所有元素。
要将所有数据放入向量中,您需要逐个使用push_back进行推送,或使用std::copy

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