6

嗨,我是新来的,所以如果有什么问题请告诉我,下次我会努力做得更好。

我试图了解下溢和上溢在 C++ 中的工作原理。我的理解是,如果超出变量的范围,它将从范围的另一端开始。因此,如果 short 的最小值是 -32768 并且我们对其执行 -1 ,则新值应该是 SHRT_MAX 。(32767)这是我的代码:

#include<iostream.h>
#include<limits.h>
#include<conio.h>
int main ( void )
{
 int testpositive =INT_MIN ;
 short testnegative = SHRT_MIN ; 
 cout<< SHRT_MIN<<"\n";
 cout << testnegative-1<<"\n";
 cout << INT_MIN << "\n";
 cout << testpositive-1 << "\n"; 
 cout<<testpositive-2;
 getch();
 return 0;
}   
4

4 回答 4

11

上溢/下溢的确切行为仅针对unsigned类型指定。

无符号整数应遵守算术模 2^n 的定律,其中 n 是该特定整数大小的值表示中的位数。

来源:草案 N3690 §3.9.1 第 4 句

这意味着无符号算术不会溢出,因为不能由得到的无符号整数类型表示的结果以比得到的无符号整数类型可以表示的最大值大一的数字为模减少。

资料来源:N3690 草案第 3.9.1 条注释 47

对于普通的有符号整数类型,C++ 标准只是简单地说,任何事情都可能发生。

如果在计算表达式期间,结果未在数学上定义或不在其类型的可表示值范围内,则行为未定义

资料来源:草案 N3690 §5 第 4 句

如果我们谈论的是 x86 处理器(或大多数其他现代处理器),那么行为确实正是您所描述的,对于 CPU,有符号值或无符号值之间没有区别(有有符号和无符号操作,但值本身只是位)。

请注意,编译器可以假设(并且大多数现代优化编译器实际上确实假设)在正确的程序中不会发生有符号整数溢出,例如在如下代码中:

int do_something();
int do_something_else();

void foo() {
    int x = do_something();
    int y = x + 1;
    if (x < y) {
        do_something();
    } else {
        do_something_else();
    }
}

编译器可以完全跳过else生成代码中的测试和分支,因为在有效程序中,带符号的 intx始终小于x+1(因为不能将带符号的溢出视为有效行为)。但是,如果您替换intunsigned int,编译器必须为 test 和 else 分支生成代码,因为对于无符号类型,它可能是x > x+1.

例如clang编译代码foo

foo():                                # @foo()
        push    rax
        call    do_something()
        pop     rax
        jmp     do_something()       # TAILCALL

您可以在其中看到 ode 只调用do_something了两次(除了对 的奇怪处理)并且实际上rax没有提及。do_something_else或多或少相同的代码由gcc.

于 2012-04-04T12:51:26.927 回答
2

有符号溢出是 C++ 中未定义的行为。

例如:

INT_MIN - 1

-INT_MIN

是调用未定义行为的表达式。

SHRT_MIN - 1并且-SHRT_MIN在具有 16 位short和 32 位的环境中不是未定义的行为,int因为通过整数提升操作数被提升到int第一个。在具有 16 位shortand的环境中int,这些表达式也是未定义的行为。

于 2012-04-04T13:08:05.537 回答
1

通常是的。但由于这是 C++,而且 C++ 受 C++ 标准规范,所以您必须知道溢出是未定义的行为

尽管您所说的可能适用于大多数平台,但不能保证,所以不要依赖它。

于 2012-04-04T12:47:31.770 回答
0

新值不一定SHRT_MAX是未定义的。

于 2012-04-04T12:47:38.960 回答