为什么由编译器决定在为变量赋予超出范围值时要分配的值

时间:2010-06-05 14:55:53

标签: c++ c compiler-construction assembly

在C ++ Primer第4版2.1.1中,它说“当为一个有符号的类型分配一个超出范围的值时,由编译器决定分配什么值”。

我无法理解。我的意思是,如果您有“char 5 = 299”之类的代码,编译器将生成asm代码,如“mov BYTE PTR _sc$[ebp], 43”(VC)或“movb $43, -2(%ebp)”(gcc + mingw),它由编译器。

但是如果我们分配一个由用户输入给出的值呢?比如,通过命令行? 生成的asm代码为“movb %al, -1(%ebp)”(gcc + mingw)和“

mov cl, BYTE PTR _i$[ebp]
mov BYTE PTR _sc$[ebp], cl

“(VC),那么现在编译器如何决定会发生什么?我想现在它是由CPU决定的。

你能给我一个明确的解释吗?

7 个答案:

答案 0 :(得分:12)

由编译器决定是否由CPU决定。 :)

C ++标准规定了程序的行为方式。编译器确保实现此行为。如果您执行标准未指定的操作,则编译器可以执行任何喜欢的操作。它可能会产生错误消息,向您的祖母发送电子邮件或破解您的银行帐户。或者它无论如何都可以生成代码,是的,然后由CPU决定接下来会发生什么。

但重点是CPU不负责确保您的程序按照C ++标准的规定运行。编译器是。因此,编译器应该如何处理与标准的任何偏差(即使它通常会选择不做任何特殊操作,这仍然是编译器的决定)

答案 1 :(得分:3)

肯定。 “在编译器中”,在这种情况下(Stanley Lippman的书)意味着“它不是由标准强迫的”。

编译器没有专门决定或必须生成用于处理此案例的代码。 它可能取决于平台。

答案 2 :(得分:3)

这将是未定义行为的示例。 C ++标准包含许多这样的句子:“如果(某些条件),结果是未定义的行为”。

为什么存在未定义的行为?这不仅仅会让事情变得更复杂吗?是的,不幸的是,程序员让事情变得更复杂。 UB的原因是为了简化编译器编写器的工作 - 要么更容易(或者根本不可能!)首先编写编译器,或者通过做出某些假设,使编译器更容易实现优化。

基本上,编写C ++程序时应遵循许多规则。编译器在编译时可以轻松检测到某些违反这些规则的行为,对于这些规则,语言要求编译器发出错误消息。一个例子就是语法错误。

但是也存在编译器难以或不可能检测到的违规。一个例子就是你在调用delete之后继续使用的一块内存。实际上theoretically impossible编写一个程序来检测每个可能的违规行为。因此,C ++标准不是要求编译器编写者解决检测这些违规的无法解决的问题,而是简单地声明如果你这样做,你的程序将会遇到“未定义的行为”。这意味着您无法对发生的事情进行任何预测 - 实际上标准示例是UB可以cause demons to fly out of your nose

[编辑] 实际上,正如litb指出的那样,您的具体案例不是未定义行为的示例,而是实现定义行为的示例,它稍微更文明。 :)此类别描述了C ++标准的作者认识到程序员可以合理地预期某种一致行为并且编译器编写者不太难实现的情况,但要求这种行为会很麻烦或适得其反。在每个实施中都是一样的。 (例如,sizeof (int)是实现定义的 - 虽然它通常是4或8,但就C ++标准而言,唯一的要求是它是>= sizeof (short)。)对于编译器来声明标准一致性,它必须记录标准中标记为“实现定义的行为”的每个场景将发生的特定行为。

答案 3 :(得分:2)

  

当然编译器会生成像

这样的asm代码

您在一个特定平台上将C ++语言与一种可能的实现混淆。

答案 4 :(得分:2)

我认为这是指这样的情况:

char c = 3456234242424 ;

3456234242424比签名的char可以容纳的大,所以它会溢出。是否应将其设置为char的最大正值或最小负值?它不是在语言标准中强制要求所以由编译器决定分配什么值

另一个常见的描述是“依赖于实现”。语言本身并不强制要做什么,但必须要做一些事情。因此,实现该语言的编译器可以/必须决定。

答案 5 :(得分:1)

对于大多数实现,当您将int分配给char时,编译器会生成访问int的低位字节的代码,并将其存储在char中。在您的示例中,命令行输入将存储在大于char的变量中,例如int,然后分配给char,截断字节。

答案 6 :(得分:0)

CPU“从不”失败,也没有任何决定,因为它们无法处理超出范围的值。在asm片段中根本没有关于超出范围值的信息,并且一旦指令正确生成就无法生成(如果操作数不符合大小,则汇编器根本不会汇编)操作,例如mov al, 123456ABh引发错误并且不产生代码,因为当然没有允许加载具有32位值的8位寄存器的指令!)。

问题完全取决于编译器和标准规范。在这种情况下,这意味着当您尝试将数字分配给无法保存它的变量时,标准不强制要求确切的行为...因此编译器实现“决定”实际发生了什么。