错误:数组下标高于 std::vector::insert 的数组边界
Posted
技术标签:
【中文标题】错误:数组下标高于 std::vector::insert 的数组边界【英文标题】:error: array subscript is above array bounds for std::vector::insert 【发布时间】:2016-08-03 16:45:01 【问题描述】:我正在使用-Werror
进行编译,发现一个警告翻译为错误:
1> cc1plus.exe: warnings being treated as errors
1> c:\rtems-4.9\bin\../lib/gcc/powerpc-rtems4.9/4.3.2/include/c++/bits/stl_vector.h: In function 'int someFunc()':
1> D:\Git\Error_Parsing_script\Src\Plus\RTEMS_proj\c:\rtems-4.9\bin\..\lib\gcc\powerpc-rtems4.9\4.3.2\include\c++\bits\stl_vector.h(1043,1) : error: array subscript is above array bounds
从此代码:
struct ControllerConfigDataType1
char name[50];
int controllerType;
;
int someFunc()
std::vector<char> reply;
reply.reserve(255);
ControllerConfigDataType1 response = 0 ;
reply.insert(reply.end(), reinterpret_cast<char*>(&response), reinterpret_cast<char*>(&response) + sizeof(response));
return 0;
据我所知,this code is completely valid。一件奇怪的事情是,如果我手动将 sizeof(resonse)
设置为 response 中的char name[50]
数组的边界,我想从我的指针取消引用reinterpret_cast<char*>(&response) + sizeof(response)
来看这是有道理的。
知道ControllerConfigDataType1
的格式不能改变,有没有办法满足编译器对这一行的保留?
请注意,这是在 RTEMS 4.9.2 的旧编译器上(请参阅下面的详细信息),这可能意味着此警告不会出现在 GCC 的更新版本中(并且不会出现在 Visual C++ 的VS2015)。
其他信息
错误中提到了stl_vector.h(1043,1)
,这是std::vector::insert
函数的实现:
// Called by the range insert to implement [23.1.1]/9
template<typename _InputIterator>
void
_M_insert_dispatch(iterator __pos, _InputIterator __first,
_InputIterator __last, __false_type)
typedef typename std::iterator_traits<_InputIterator>::
iterator_category _IterCategory;
_M_range_insert(__pos, __first, __last, _IterCategory());
从库中检索到的缩进
请注意,编译器由RTEMS 4.9.2
提供,并具有以下版本信息:
Thread model: rtems
gcc version 4.3.2 (GCC)
【问题讨论】:
每当我在代码审查中看到reinterpret_cast
时,我都会开始寻找错误(特别小心)(除了演员表本身)——通常会有一些.. 只是说。
"gcc 版本 4.3.2" - 这很旧。与您的问题完全无关,但您是否考虑过使用更现代的编译器(和 C++ 语言版本)?
@JesperJuhl 1. 是的,但这是必要的,我们一直非常小心。 2.我们不能,它与操作系统相关,并且操作系统更新将是一个6个月 - 1年的项目,没有资源。
Downvoter,解释我可以改进什么的评论会很有帮助,这真的是一个糟糕的问题吗?
【参考方案1】:
获取对象字节的一个好方法是使用memcpy
,并将字节类型设为unsigned char
。这很好,因为神圣标准至少有一个例子,所以如果编译器阻塞它,那么很容易说,嘿,这个编译器阻塞了标准中的一个例子,让我们停止使用它。即使 ISO 标准中的示例不规范。
您的原始示例,采用这种方法:
int someFunc1()
std::vector<unsigned char> reply;
reply.reserve(255); // Note: this, from original example, is only an optimization.
ControllerConfigDataType1 response = 0 ;
// reply.insert(reply.end(), reinterpret_cast<char*>(&response), reinterpret_cast<char*>(&response) + sizeof(response));
int rs = reply.size(); int ds = sizeof(response); reply.resize(rs+ds); memcpy(&reply[rs], &response, ds);
return 0;
此代码假定 int
足以满足此处使用的 vector
的大小,这对于网络数据包来说是合理的:它不可能是 2 GB 或更多。否则将int
替换为ptrdiff_t
。可能重命名为Size
。
更一般地,您可以将其抽象化并集中化,这有助于测试和维护,如下所示:
#include <stddef.h> // ptrdiff_t
#include <string.h> // memcpy
#include <type_traits> // std::is_trivially_copyable
#include <utility> // std::enable_if_t
using Byte = unsigned char;
using Size = ptrdiff_t;
template< class Type
// The following sanity-check line must be removed for a C++03 compiler:
, class Enabled_ = std::enable_if_t< std::is_trivially_copyable< Type >::value >
>
void append_to( std::vector<Byte>& v, Type const& o )
Size const n_v_bytes = v.size();
Size const n_o_bytes = sizeof( o );
v.resize( n_v_bytes + n_o_bytes );
memcpy( &v[n_v_bytes], &o, n_o_bytes );
【讨论】:
愚蠢的反对票,请解释你的愚蠢反对票。 这并不能回答问题,这就是投票失败的原因。问题是“为什么我有编译器警告”,你愚蠢的答案是“使用 memcpy”。 我们从memcpy
转移到 std::vector
以使内存易于扩展,但我们并不想搬回去,但不是我的反对意见。
@Paul:你的意见没有回答这个问题。您能否详细说明一下,您认为它如何无法回答问题?我对你的想法很感兴趣(一般现象)。
@Ben:你可以使用memcpy
和std::vector
,这不是问题。以上是关于错误:数组下标高于 std::vector::insert 的数组边界的主要内容,如果未能解决你的问题,请参考以下文章