91

我正在学习 C++ 中的函数重载并遇到了这个问题:

void display(int a)
{
    cout << "int" << endl;
}

void display(unsigned a)
{
    cout << "unsigned" << endl;
}

int main()
{
    int i = -2147483648;
    cout << i << endl; //will display -2147483648
    display(-2147483648);
}

据我了解,int范围内给出的任何值(在我的情况下int是 4 字节)都会调用display(int),并且此范围之外的任何值都将是模棱两可的(因为编译器无法决定调用哪个函数)。它对int除最小值以外的所有值都有效,即-2147483648编译失败并出现错误

重载的调用display(long int)不明确

但是对 a 取相同的值int并打印该值给出2147483648. 我真的对这种行为感到困惑。

为什么只有在传递最大负数时才会观察到这种行为?(如果 ashort-32768- 事实上,在负数和正数具有相同二进制表示的任何情况下,行为是相同的)

使用的编译器:g++ (GCC) 4.8.5

4

3 回答 3

145

这是一个非常微妙的错误。您所看到的是 C++ 中没有负整数文字的结果。如果我们查看 [lex.icon] 我们会得到一个integer-literal

integer-literal
        decimal-literal 整数后缀opt
        [...]

可以是十进制文字

十进制文字:
        非零位
        十进制文字'选择数字

其中digit[0-9]非零位[1-9],后缀 par 可以是u, U, l, L, ll, 或之一LL。这里没有任何地方包含-作为十进制文字的一部分。

在 §2.13.2 中,我们还有:

整数文字是没有句点或指数部分的数字序列,可选的分隔单引号在确定其值时被忽略。整数文字可能有一个指定其基数的前缀和一个指定其类型的后缀。数字序列的词汇第一个数字是最重要的。十进制整数文字(以十为基数)以 0 以外的数字开头,由一系列十进制数字组成。

(强调我的)

这意味着-in-2147483648是一元的operator -。这意味着-2147483648实际上被视为-1 * (2147483648). 因为2147483648对你来说太多了,int所以它被提升为 along int并且歧义来自不匹配。

如果您想以可移植的方式获取类型的最小值或最大值,您可以使用:

std::numeric_limits<type>::min();  // or max()
于 2017-08-02T19:21:41.600 回答
36

该表达式-2147483648实际上是将-运算符应用于常量2147483648。在您的平台上,int不能存储2147483648,它必须用更大的类型表示。因此,表达式-2147483648没有被推导出为signed int更大的有符号类型,signed long int

由于您没有为编译器提供重载,long因此编译器被迫在两个同样有效的重载之间进行选择。您的编译器应该发出关于模棱两可重载的编译器错误。

于 2017-08-02T19:21:16.150 回答
4

扩展其他人的答案


为了澄清为什么 OP 感到困惑,首先:考虑下面的signed int二进制表示2147483647

最大的有符号整数




接下来,在这个数字上加一个:给另一个signed int-2147483648OP希望使用) 最小的有符号整数



最后:我们可以看到为什么 OP 在-2147483648编译为 along int而不是 a时会感到困惑signed int,因为它显然适合 32 位。

但是,正如当前答案所提到的,一元运算符 ( -)解析2147483648which is along int并且不适合 32 位后应用。

于 2017-08-08T22:02:06.223 回答