我知道整数下溢和溢出是未定义的。
但是,考虑到C ++最终编译为汇编,实际上是不是定义了行为?
按位表示保持不变,整数格式保持不变0111..11将始终翻转到1000..00,对于下溢相同,那么为什么不将其视为已定义的行为?
关于汇编汇编,我是从我们在学校教过的基本程序集中得出的,但代码块给出了
int x = INT_MAX;
int y = x+1;
编译到
00401326 movl $0x7fffffff,0x8(%esp)
0040132E mov 0x8(%esp),%eax
00401332 inc %eax
00401333 mov %eax,0xc(%esp)
现在,无论x的值如何,总是会有inc或add指令?那么,未定义的行为出现在哪里?
答案 0 :(得分:6)
但是,鉴于C ++最终编译为汇编,实际定义的行为是不是?
不,因为编译器决定它发出什么样的程序集。如果编译器希望,它可以生成在遇到未定义行为时擦除硬盘的程序集。
(实际上,“C ++最终编译成汇编”可能不是真的。存在C++ interpreters, for example - 标准没有规定C ++应该如何编译/编译。
标准的创建者决定不定义的原因之一是 - 几乎总是 - 优化的机会。如果有符号溢出是UB,那么编译器可以假设x + 1 > x
始终为真,并生成依赖于此前提条件的更简单/更短/更快的代码。
答案 1 :(得分:5)
在C ++标准中未定义有符号整数的溢出,正是因为不同的编译器,汇编器和平台可能会以不同的方式解释它们。
当你知道一个程序会运行时,你可以推断一个程序的行为,但是如果没有这方面的知识就不可能预测它的行为方式。
按位表示保持不变,整数格式保持不变
这根本不是真的。
答案 2 :(得分:0)
假设每字节8位/ char
。这会给我们:
std::numeric_limits<char>::max()
std::numeric_limits<char>::min()
您可以看到最小值,即我们有不同的位模式和最小值,而最大值是相同的。
那么,如果你最多加1会怎么样?让我们假设我们转为无符号,加1,转回签名。结果将是:
相当混乱。但是,如果我们想要明确定义溢出,我们能做什么?我们假设我们有一个signed char c = 127;
并且想要添加1.我们可以定义结果应该始终为-127,因为所有三个引用的系统都可以表示(忽略这些不是&# 39; t唯一表示有符号整数的系统)。但这意味着编译器必须专门捕获溢出并在2的补码(大多数系统)和签名的幅度系统上正确处理它,这意味着额外的指令,因此在那些机器上的性能不太理想。
你不太可能遇到一台在现实生活中没有使用2的补充机器,所以C ++人员不能简单地强制要求吗?我还没有发现任何当前的 CPU或DSP使用除2的补充以外的任何东西,但是当C ++创建时, 机器使用1&# 39; s补码(例如CDC Cyber),听到有些DSP今天仍然存在(毕竟有DSP有char
sizes other than 8 bit),我不会感到惊讶。这就是为什么它保持未定义的行为。