为什么C++数组索引值是有符号的,而不是围绕size_t类型构建的(或者我错了)
Why are C++ array index values signed and not built around the size_t type (or am I wrong in that)?
对我来说,跟踪不断发展的C++标准变得越来越困难,但现在对我来说似乎很清楚的一件事是数组索引值应该是整数(不是long long
或size_t
或其他一些看似更合适的大小选择)。我从这个问题的答案(C++数组索引的类型)以及成熟的C++库(如 Qt)使用的实践中推测了这一点,这些库也使用简单的整数作为大小和数组索引运算符。 对我来说,棺材上的钉子是我现在收到来自MSVC 2017的大量编译器警告,指出我的const unsigned long long
(又名const size_t
)变量在用作数组索引时被隐式转换为类型const int
。
Mat在上面链接的问题中给出的答案引用了ISO C++标准草案n3290的话
它应是一个整数常数表达式,其值应大于零。
我没有阅读这些规范和精确解释其语言的背景,所以也许有几点澄清:
-
"整型常量表达式">是否特别禁止像
long long
这样对我来说是整型的东西,只是一个更大的尺寸? - 他们所说的是否特别禁止像
size_t
这样标记为unsigned
的类型?
如果我在这里看到的都是真的,那么数组索引值应该是signed int
类型,为什么?这对我来说似乎是违反直觉的。规范甚至指出表达式"应大于零">,因此如果它是signed
,我们会浪费一点。当然,我们可能仍然希望以某种方式将索引与0
进行比较,这对于unsigned
类型来说是危险的,但是应该有更便宜的方法来解决这个问题,只浪费一个值,而不是整个位。
此外,随着寄存器的不断扩大,一个更面向未来的解决方案是允许索引的更大类型(如long long
),而不是坚持使用int
这在历史上无论如何都是有问题的类型(当处理器更改为32 bits
时更改其大小,然后当它们转到64 bits
时不更改)。 我什至看到有些人谈论size_t
轶事,就像它被设计成一种更面向未来的类型,用于尺寸(而不仅仅是为sizeof
操作员服务返回的类型)。但当然,这可能是杜撰的。
我只是想确保我在这里的基础编程理解没有缺陷。当我看到像ISO C++小组这样的专家在做某事,或者Qt的工程师时,我会怀疑他们有充分的理由!对于像数组索引这样对编程如此基础的东西,我觉得我需要知道这个原因是什么,否则我可能会错过一些重要的东西。
查看 [expr.sub]/1 我们有
后缀表达式后跟方括号中的表达式是后缀表达式。其中一个表达式应为"T 数组"类型的 glvalue 或类型为"指向 T 的指针"的 prvalue,另一个表达式应为无作用域枚举或整型的 prvalue。结果的类型为"T"。67 表达式 E1[E2] (根据定义)与 *((E1)+(E2))相同),只是在数组操作数的情况下,如果该操作数是左值,则结果为左值,否则为 x值。表达式 E1 在表达式 E2 之前排序。
强调我的
因此,下标运算符的索引必须是无作用域枚举或整型。 在[basic.fundamental]中,我们看到标准整数类型是signed char
、short int
、int
、long int
和long long int
,以及它们的无符号对应物。
因此,任何标准整数类型都可以使用,任何其他整数类型(如size_t
)都是用作数组索引的有效类型。 提供给下标运算符的值甚至可以具有负值,只要该值可以访问有效元素即可。
我认为标准库 API 更喜欢索引是无符号类型。如果您查看文档以了解std::size_t
它指出
在索引C++容器(如
std::string
、std::vector
等)时,适当的类型是此类容器提供的成员 typedefsize_type
。它通常被定义为std::size_t
的同义词。
在查看诸如std::vector::at
等功能的签名时,这一点得到了加强
reference at( size_type pos );
const_reference at( size_type pos ) const;
我认为您混淆了两种类型:
第一种类型是可用于定义数组大小的对象/值的类型。不幸的是,您链接到的问题使用索引,他们应该使用数组大小。这必须是必须在编译时计算的表达式,并且其值必须大于零。
int array[SomeExpression]; // Valid as long as SomeExpression can be evaluated // at compile time and the value is greater than zero.
第二种类型是可用于访问数组的对象/值的类型。鉴于上述
array
,array[i] = SomeValue; // i is an index to access the array
i
不需要在编译时计算,i
必须在 [0, SomeExpression-1] 范围内。但是,可以使用负值作为索引来访问数组。由于array[i]
被计算为*(array+i)
(暂时忽略重载的operator[]
函数),如果array
恰好指向数组的中间,i
可以是负值。我对另一篇SO帖子的回答提供了有关该主题的更多信息。顺便说一句,由于
array[i]
被评估为*(array+i)
,因此使用i[array]
是合法的,并且与array[i]
相同。
- ArduinoJson 6.15.2:JsonObject没有命名类型
- 防止主数据类型C++的隐式转换
- 大量序列中核苷酸类型的快速计数
- 如何从C++中的依赖类型中获得它所依赖的类型
- C++,OpenCV,尝试显示图像时"OpenCV(4.3.0) Error: Assertion failed (size.width>0 && size.height>0)"此错误
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如何获取std::result_of函数的返回类型
- 从父命名空间重载类型
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 为什么我必须在初始化 std::array<SomeStruct, size> 时指定每个项目的类型C++
- 数组类型 'float [size]'不可分配
- 请求使用 .empty 或 .size 的非类类型的成员
- 如何声明将使用 map.size() 计算的 int 类型
- 为什么 std::array::size constexpr 具有简单类型(int、double、..),而不是 std
- 为什么引用类型的sizeof会给你该类型的size
- 可以将vector.size()的结果存储到int类型的变量中吗
- c++中string.size()的类型是什么?
- 表达式必须具有size()的类类型