The as-if rule

来自cppreference.com
< cpp‎ | language

 
 
C++ 语言
表达式
替代表示
字面量
布尔 - 整数 - 浮点
字符 - 字符串 - nullptr (C++11)
用户定义 (C++11)
工具设施
特性 (C++11)
类型
typedef 声明
类型别名声明 (C++11)
强制转换
隐式类型转换 - 显式类型转换
static_cast - dynamic_cast
const_cast - reinterpret_cast
内存分配
类特有的函数属性
特殊成员函数
模板
杂项
 

允许任何和所有的不改变程序可观察的行为的代码转换

目录

[编辑] 解释

C++编译器被允许对程序进行任何修改,只要保证以下几点:

  • 对volatile对象访问(读取和写入)的顺序和代码所写的相同。
  • 在程序终止时,写入的所有文件的数据是完全一样的,仿佛程序是按照所写代码执行的。
  • 所有输入和输出操作都和代码所写的发生的顺序和内容相同。

[编辑] 注释

因为编译器(通常情况下)无法进行分析一个外部库的代码,以确定它是否执行I/O或访问volatile对象,因此第三方库的调用同样不受这种编译器优化的影响。然而,标准的库调用可能被其他调用所取代,消除,或在优化过程被中添加到程序中。

有不确定行为的程序,例如,由于访问一个数组越界、修改const对象、求值顺序违规行为等,都不受as-if规则约束:在不同的编译优化选项下进行编译时,它们经常改变可观察到的行为。例如,如果有符号整数溢出测试依赖于该溢出的结果,例如if(n+1 < n) abort();it is removed entirely by some compilers因为签署溢出是不确定的行为编译优化器可以假设这种情况绝不会发生,对这种情况是否发生的检测是冗余的。

复制省略是唯一被定义的as-if规则的例外。

[编辑] 示例

int& preinc(int& n) { return ++n; }
int add(int n, int m) { return n+m; }
 
// volatile input to prevent constant folding
volatile int input = 7;
 
// volatile output to make the result a visible side-effect
volatile int result;
 
int main()
{
    int n = input;
// using built-in operators would invoke undefined behavior
//    int m = ++n + ++n;
// but using functions makes sure the code executes as-if 
// the functions were not overlapped
    int m = add(preinc(n), preinc(n));
    result = m;
}

输出:

# full code of the main() function as produced by the GCC compiler
# x86 (Intel) platform:
        movl    input(%rip), %eax   # eax = input
        leal    3(%rax,%rax), %eax  # eax = 3 + eax + eax
        movl    %eax, result(%rip)  # result = eax
        xorl    %eax, %eax          # eax = 0 (the return value of main())
        ret
 
# PowerPC (IBM) platform:
        lwz 9,LC..1(2)
        li 3,0          # r3 = 0 (the return value of main())
        lwz 11,0(9)     # r11 = input;
        slwi 11,11,1    # r11 = r11 << 1;
        addi 0,11,3     # r0 = r11 + 3;
        stw 0,4(9)      # result = r0;
        blr
 
# Sparc (Sun) platform:
        sethi   %hi(result), %g2
        sethi   %hi(input), %g1
        mov     0, %o0                 # o0 = 0 (the return value of main)
        ld      [%g1+%lo(input)], %g1  # g1 = input
        add     %g1, %g1, %g1          # g1 = g1 + g1
        add     %g1, 3, %g1            # g1 = 3 + g1
        st      %g1, [%g2+%lo(result)] # result = g1
        jmp     %o7+8
        nop
 
# in all cases, the side effects of preinc() were eliminated, and the
# entire main() function was reduced to the equivalent of result = 2*input + 3;

[编辑] 另请参阅