常量折叠

 

 

/* 看下面这句的反汇编代码

cout << a << ", " << *p << endl;

00B11547 mov         esi,esp

00B11549 mov         eax,dword ptr [__imp_std::endl (0B1A340h)]

00B1154E push        eax

00B1154F mov         edi,esp

00B11551 mov         ecx,dword ptr [p]

00B11554 mov         edx,dword ptr [ecx]

00B11556 push        edx

00B11557 push        offset string ", " (0B17800h)

00B1155C mov         ebx,esp

00B1155E push        1 // 关键看这一句,注意到输出打印a的值的时候传进去的并不是a

// 这个到底是哪来的,就是从我们的常量表里来的。

00B11560 mov         ecx,dword ptr [__imp_std::cout (0B1A344h)]

00B11566 call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0B1A32Ch)]

00B1156C cmp         ebx,esp

00B1156E call        @ILT+420(__RTC_CheckEsp) (0B111A9h)

00B11573 push        eax

00B11574 call        std::operator<<<std::char_traits<char> > (0B11159h)

00B11579 add         esp,8

00B1157C mov         ecx,eax

00B1157E call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0B1A32Ch)]

00B11584 cmp         edi,esp

00B11586 call        @ILT+420(__RTC_CheckEsp) (0B111A9h)

00B1158B mov         ecx,eax

00B1158D call        dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0B1A34Ch)]

00B11593 cmp         esi,esp

00B11595 call        @ILT+420(__RTC_CheckEsp) (0B111A9h)

 

 

总结:编译器会为常量分配了地址,但是在使用常量的时,常量会被一立即数替换(保护常量,防止被破坏性修改)

 

### 常量折叠优化的限制条件与失效场景 常量折叠是一种编译时优化技术,旨在将可以在编译阶段计算出结果的表达式直接替换为其结果,从而减少运行时的计算开销。然而,这种优化并非在所有情况下都能被应用,其限制条件和失效场景主要包括以下几种情况: 1. **运行时变量参与表达式计算** 当表达式中包含在运行时才能确定值的变量时,编译器无法进行常量折叠。例如,非 `final` 修饰的变量可能在运行时被修改,其值在编译时无法确定。这种情况下,编译器无法将表达式视为常量,从而无法进行优化[^1]。 ```java int a = 5; int b = 10; int c = a + b; // 此处 a 和 b 不是 final 变量,无法进行常量折叠 ``` 2. **涉及副作用的操作** 如果表达式中的某些操作会产生副作用(如函数调用、I/O 操作、修改全局变量等),则编译器通常不会进行常量折叠。因为折叠这些表达式可能会导致副作用丢失,从而影响程序行为。 ```java int x = someFunction() + 5; // someFunction() 可能有副作用,无法进行常量折叠 ``` 3. **动态加载的类或反射机制** 在 Java 等语言中,如果表达式依赖于运行时动态加载的类或通过反射机制获取的值,则编译器无法在编译时确定其值,因此无法进行常量折叠。 4. **浮点数精度问题** 某些浮点数运算在编译时可能会因精度问题而无法被折叠。例如,涉及浮点数的舍入误差、NaN(非数字)或无穷大的表达式,可能导致编译器无法安全地进行折叠[^2]。 ```java double d = 0.1 + 0.2; // 浮点精度问题可能导致无法进行常量折叠 ``` 5. **编译器优化级别限制** 常量折叠依赖于编译器优化级别。如果编译器被配置为较低的优化级别(如 `-O0`),则可能不会执行常量折叠优化。在较高优化级别(如 `-O2` 或 `-O3`)下,编译器会尝试进行更多常量折叠操作[^2]。 6. **跨模块或跨文件的常量引用** 如果表达式中引用的常量定义在另一个模块或文件中,并且该常量不是 `inline` 或 `constexpr`(在 C++ 中),则编译器可能无法在当前模块中进行常量折叠,因为其值在当前编译单元中不可见。 7. **使用 `volatile` 修饰的变量** 在 C/C++ 中,`volatile` 修饰的变量表示其值可能在程序之外被修改(例如由硬件或中断处理程序)。因此,编译器不会对涉及 `volatile` 变量的表达式进行常量折叠。 ```cpp volatile int flag = 1; int result = flag + 5; // 由于 flag 是 volatile,无法进行常量折叠 ``` 8. **泛型或模板参数依赖** 在 C++ 模板编程中,如果表达式依赖于模板参数或泛型类型,且这些参数在实例化时才确定,则编译器可能无法在早期阶段进行常量折叠。 9. **异常处理或控制流依赖** 如果表达式的结果依赖于异常处理机制或控制流结构(如 `if`、`switch`、`try-catch` 等),则编译器无法在编译时确定其值,因此无法进行常量折叠。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值