从矢量写入/读取的奇怪行为
Strange behavior with with writing / reading from vector
我坐在这里看了几个小时的代码,但我就是不明白。
它是关于 std::vector canData 的,它用作解码和编码来自 CAN DBC 解析器的数据的缓冲区。
我的问题的完整示例是 here.
基本上有一个值编码到一个数组,然后从这个数组再次解码。但是这个数组的大小始终为零,即使在清除数组后,尽管它为零,但仍然可以从中解码数据。
有人可以给我解释一下吗?
我错过了什么吗?
unsigned int canIdentifier = 0x100;
std::vector<std::uint8_t> canData;
canData.reserve(4);
network.messages[canIdentifier].signals["multiplexor"].encode(canData, 0);
network.messages[canIdentifier].signals["signal_1"].encode(canData, 0x12);
std::cout << "size: " << canData.size() << std::endl;
canData.clear();
decodeMessage(canIdentifier, canData);
std::cout << "2size: " << canData.size() << std::endl;
更新所需函数:
uint64_t Signal::decode(std::vector<uint8_t> & data)
{
/* safety check */
if (bitSize == 0) {
return 0;
}
/* copy bits */
uint64_t retVal = 0;
if (byteOrder == ByteOrder::BigEndian) {
/* start with MSB */
unsigned int srcBit = startBit;
unsigned int dstBit = bitSize - 1;
for (unsigned int i = 0; i < bitSize; ++i) {
/* copy bit */
if (data[srcBit / 8] & (1 << (srcBit % 8))) {
retVal |= (1ULL << dstBit);
}
/* calculate next position */
if ((srcBit % 8) == 0) {
srcBit += 15;
} else {
--srcBit;
}
--dstBit;
}
} else {
/* start with LSB */
unsigned int srcBit = startBit;
unsigned int dstBit = 0;
for (unsigned int i = 0; i < bitSize; ++i) {
/* copy bit */
if (data[srcBit / 8] & (1 << (srcBit % 8))) {
retVal |= (1ULL << dstBit);
}
/* calculate next position */
++srcBit;
++dstBit;
}
}
/* if signed, then fill all bits above MSB with 1 */
if (valueType == ValueType::Signed) {
if (retVal & (1 << (bitSize - 1))) {
for (unsigned int i = bitSize; i < 8 * sizeof(retVal); ++i) {
retVal |= (1ULL << i);
}
}
}
return retVal;
}
void Signal::encode(std::vector<uint8_t> & data, uint64_t rawValue)
{
/* safety check */
if (bitSize == 0) {
return;
}
/* copy bits */
if (byteOrder == ByteOrder::BigEndian) {
/* start with MSB */
unsigned int srcBit = startBit;
unsigned int dstBit = bitSize - 1;
for (unsigned int i = 0; i < bitSize; ++i) {
/* copy bit */
if (rawValue & (1ULL << dstBit)) {
data[srcBit / 8] |= (1 << (srcBit % 8));
} else {
data[srcBit / 8] &= ~(1 << (srcBit % 8));
}
/* calculate next position */
if ((srcBit % 8) == 0) {
srcBit += 15;
} else {
--srcBit;
}
--dstBit;
}
} else {
/* start with LSB */
unsigned int srcBit = startBit;
unsigned int dstBit = 0;
for (unsigned int i = 0; i < bitSize; ++i) {
/* copy bit */
if (rawValue & (1ULL << dstBit)) {
data[srcBit / 8] |= (1 << (srcBit % 8));
} else {
data[srcBit / 8] &= ~(1 << (srcBit % 8));
}
/* calculate next position */
++srcBit;
++dstBit;
}
}
}
一步步看代码:
canData.reserve(4);
为可以包含(至少)4 个 uint8_t 但包含 0 个(canData.resize(4) 会改变向量大小)的向量分配内存。 canData.capacity() 然后是 4(或更多),但 canData.size() 是 0。
encode(...) 方法使用 operator[] 访问向量。它不检查索引是否在范围内(因此小于 canData.size()),因此没有异常(如果使用 vector at() 而不是它会抛出)。此外,由于访问的索引位于分配的内存中,因此不会发生任何不良情况(特别是内存泄漏)。
canData.clear()
销毁范围内的所有矢量元素,因此在索引 0 和 canData.size() 之间。因此,它不会触及 canData.size() 以上的元素,在本例中为 0。 clear() 也不收缩分配给 vector 的内存(或者不保证重新分配到收缩内存)——shrink_to_fit() 会这样做。
最后,decodeMessage 对分配并填充了正确数据且未被破坏的内存进行操作。同样,矢量运算符 [] 的使用不会导致异常/内存泄漏。
如评论中所述,有很多未定义的行为。
我坐在这里看了几个小时的代码,但我就是不明白。 它是关于 std::vector canData 的,它用作解码和编码来自 CAN DBC 解析器的数据的缓冲区。 我的问题的完整示例是 here.
基本上有一个值编码到一个数组,然后从这个数组再次解码。但是这个数组的大小始终为零,即使在清除数组后,尽管它为零,但仍然可以从中解码数据。
有人可以给我解释一下吗?
我错过了什么吗?
unsigned int canIdentifier = 0x100;
std::vector<std::uint8_t> canData;
canData.reserve(4);
network.messages[canIdentifier].signals["multiplexor"].encode(canData, 0);
network.messages[canIdentifier].signals["signal_1"].encode(canData, 0x12);
std::cout << "size: " << canData.size() << std::endl;
canData.clear();
decodeMessage(canIdentifier, canData);
std::cout << "2size: " << canData.size() << std::endl;
更新所需函数:
uint64_t Signal::decode(std::vector<uint8_t> & data)
{
/* safety check */
if (bitSize == 0) {
return 0;
}
/* copy bits */
uint64_t retVal = 0;
if (byteOrder == ByteOrder::BigEndian) {
/* start with MSB */
unsigned int srcBit = startBit;
unsigned int dstBit = bitSize - 1;
for (unsigned int i = 0; i < bitSize; ++i) {
/* copy bit */
if (data[srcBit / 8] & (1 << (srcBit % 8))) {
retVal |= (1ULL << dstBit);
}
/* calculate next position */
if ((srcBit % 8) == 0) {
srcBit += 15;
} else {
--srcBit;
}
--dstBit;
}
} else {
/* start with LSB */
unsigned int srcBit = startBit;
unsigned int dstBit = 0;
for (unsigned int i = 0; i < bitSize; ++i) {
/* copy bit */
if (data[srcBit / 8] & (1 << (srcBit % 8))) {
retVal |= (1ULL << dstBit);
}
/* calculate next position */
++srcBit;
++dstBit;
}
}
/* if signed, then fill all bits above MSB with 1 */
if (valueType == ValueType::Signed) {
if (retVal & (1 << (bitSize - 1))) {
for (unsigned int i = bitSize; i < 8 * sizeof(retVal); ++i) {
retVal |= (1ULL << i);
}
}
}
return retVal;
}
void Signal::encode(std::vector<uint8_t> & data, uint64_t rawValue)
{
/* safety check */
if (bitSize == 0) {
return;
}
/* copy bits */
if (byteOrder == ByteOrder::BigEndian) {
/* start with MSB */
unsigned int srcBit = startBit;
unsigned int dstBit = bitSize - 1;
for (unsigned int i = 0; i < bitSize; ++i) {
/* copy bit */
if (rawValue & (1ULL << dstBit)) {
data[srcBit / 8] |= (1 << (srcBit % 8));
} else {
data[srcBit / 8] &= ~(1 << (srcBit % 8));
}
/* calculate next position */
if ((srcBit % 8) == 0) {
srcBit += 15;
} else {
--srcBit;
}
--dstBit;
}
} else {
/* start with LSB */
unsigned int srcBit = startBit;
unsigned int dstBit = 0;
for (unsigned int i = 0; i < bitSize; ++i) {
/* copy bit */
if (rawValue & (1ULL << dstBit)) {
data[srcBit / 8] |= (1 << (srcBit % 8));
} else {
data[srcBit / 8] &= ~(1 << (srcBit % 8));
}
/* calculate next position */
++srcBit;
++dstBit;
}
}
}
一步步看代码:
canData.reserve(4);
为可以包含(至少)4 个 uint8_t 但包含 0 个(canData.resize(4) 会改变向量大小)的向量分配内存。 canData.capacity() 然后是 4(或更多),但 canData.size() 是 0。
encode(...) 方法使用 operator[] 访问向量。它不检查索引是否在范围内(因此小于 canData.size()),因此没有异常(如果使用 vector at() 而不是它会抛出)。此外,由于访问的索引位于分配的内存中,因此不会发生任何不良情况(特别是内存泄漏)。
canData.clear()
销毁范围内的所有矢量元素,因此在索引 0 和 canData.size() 之间。因此,它不会触及 canData.size() 以上的元素,在本例中为 0。 clear() 也不收缩分配给 vector 的内存(或者不保证重新分配到收缩内存)——shrink_to_fit() 会这样做。
最后,decodeMessage 对分配并填充了正确数据且未被破坏的内存进行操作。同样,矢量运算符 [] 的使用不会导致异常/内存泄漏。
如评论中所述,有很多未定义的行为。