【发布时间】:2020-01-05 07:32:04
【问题描述】:
我的代码出现错误行为。调查它让我找到一个显示问题的简短示例:
//g++ 5.4.0
#include <iostream>
#include <vector>
int main()
{
std::vector<short> v(20);
auto D = &v[5] - &v[10];
auto C = D / sizeof(short);
std::cout << "C = " << C;
}
这个例子很常见。打印出来的结果是什么?
C = 9223372036854775805
在这里测试:https://rextester.com/l/cpp_online_compiler_gcc 还针对 Clang C++、VS C++ 和 C 进行了测试。结果一样。
在与同事讨论时,我被指向了文档https://en.cppreference.com/w/cpp/language/operator_arithmetic#Conversions。
它告诉我们:
- 如果两个操作数都带符号或都无符号,则转换等级较低的操作数将转换为整数转换等级较高的操作数
- 否则,如果无符号操作数的转换等级大于或等于有符号操作数的转换等级,则将有符号操作数转换为无符号操作数的类型。
- 否则,如果有符号操作数的类型可以表示无符号操作数的所有值,则将无符号操作数转换为有符号操作数的类型
看来 second 规则在这里起作用。但它不是正确的。
为了确认第二规则,我测试了这样的例子:
//g++ 5.4.0
#include <iostream>
int main()
{
typedef uint32_t u_t; // uint64_t, uint32_t, uint16_t uint8_t
typedef int32_t i_t; // int64_t, int32_t, int16_t int8_t
const u_t B = 2;
const i_t X = -1;
const i_t A1 = X * B;
std::cout << "A1 = X * B = " << A1 << "\n";
const i_t C = A1 / B; // signed / unsigned division
std::cout << "A1 / B = " << C << "\n";
}
使用 u_t 和 i_t 的不同 rank 组合,发现它适用于任何组合,EXCEPT对于 32 和 64 位(int64_t/uint64_t 和 int32_t/uint32_t)。所以 second 规则 DOES NOT 适用于 16 和 8 位。
注意:乘法 操作在所有情况下都正常工作。所以这只是除法问题。
SECOND 规则听起来也是错误的:
有符号操作数转换为无符号操作数的类型
signed 不能转换成 unsigned - 它是一个 !! NEGATIVE 值错误!!! 但相反的转换是正确的 - 无符号操作数被转换为有符号操作数的类型
看着这个我可以注意到这是 C++ 标准算术运算中的一个可能的错误。 而不是:
Otherwise, if the unsigned operand's conversion rank is greater or equal to the conversion rank of the signed operand, the signed operand is converted to the unsigned operand's type.
应该是:
Otherwise, if the signed operand's conversion rank is greater or equal to the conversion rank of the unsigned operand, the unsigned operand is converted to the signed operand's type.
在我看来,如果满足 signed 和 unsigned multiplication/division 那么 unsigned 操作数被转换为 signed ,然后它被转换为正确的等级。至少 x86 汇编器 跟在它后面。
请解释一下这里哪里出错了。我希望这篇文章中的第一个测试适用于代替 auto 类型所涉及的任何类型,但现在它不可能并且C++标准 em> 表明这是正确的行为。
很抱歉提出一个奇怪的问题,但我遇到了这个问题。我在 C/C++ 上编码 30 年,但这是我无法清楚解释的第一个问题 - 无论是错误还是预期行为。
【问题讨论】:
-
sizeof(short)的类型为std::size_t(无符号)。 -
auto C = -5 / 2UL;就足够了。
标签: c++ standards division integer-arithmetic