编译期常量技术如何避免
A. 关于C++编译期间类里的常量问题
cout <<那句 你把(const string) 这个去掉呢 或者直接把cp声明成string* 然后直接cout << *cp 好了
B. c语言 为什么编译器提示必须有常量值,到底哪错了
matrix是一个数组,而定义一个数组的长度必须得是一个常量,也就是N,而你的N不是常量,所以将N定义为常量即可
C. C语言中系统既然不给常量分配存储空间,那么编译系统又是如何"记忆"和使用常量的呢
耐心看完,你应该能明白了:
C语言中,常量和变量是放在不同的"段"(section)里,程序一旦加载,常量/变量自然都在内存里了。
常量和全程变量,放在初始化段。
局部变量,通常在栈里。
常量在程序加载时同时加载。
D. java如何优化编译呢
#java编译器对`String常量表达式`的优化:
- 1.String+String 可以被编译器识别为常量表达
String a="ab" ;
String b="a"+"b";//编译后:b="ab"
System.out.println(a==b);//true
分析:
编译器将"a"+"b"当做常量表达式,在编译时期进行优化,直接取"ab". 在运行时期
并没有创建新的对象,而是从jvm字符串常量池中获取之前已经存在的"ab"对象.
- 2.String+基本类型 可以被编译器识别为常量表达式
String a="a1";
String b="a"+1; //"a1"
String c="a"+true;//"atrue"
String d="a"+3.14;//"a3.14"
#java编译器对`常量`优化:
* 它是编译时的一项优化技术,将代码的常量计算在编译期完成,节约了运行时的计算量.
1.常量替换
//编译前:
final int x=10;
int y=x;
//编译后
int x=10;
int y=10;//编译时,常量替换了
2.数学恒等式的模式匹配替换
//编译前:
int x=10+10;
//编译后
int x=20;//编译时,模式匹配替换了
3.常量折叠
//编译前:
boolean flag=true||(a || b && c);
//编译后
boolean flag=true;//编译时,常量折叠了
E. java中编译期常量所指的是什么
classInitalizedClass{
static{
System.out.println("!");
}
publicstaticintinititalize_varible=1;
}
{
publicstaticvoidmain(String[]args){
System.out.println(InitalizedClass.inititalize_varible);
}
}
上面的结果是:
!
1
classInitalizedClass{
static{
System.out.println("!");
}
//和上面的例子唯一的差异就是此处的变量INITIALIZED_VARIBLE被声明为final
_VARIBLE=1;
}
{
publicstaticvoidmain(String[]args){
System.out.println(InitalizedClass.INITIALIZED_VARIBLE);
}
}
上面的结果是:
1
为什么两个例子执行结果不一样,原因是第二个例子中的INITIALIZED_VARIBLE为编译期常量,它不会导致类的初始化的
F. 如何防止JAVA程序源代码被反编译
我们都知道JAVA是一种解析型语言,这就决定JAVA文件编译后不是机器码,而是一个字节码文件,也就是CLASS文件。而这样的文件是存在规律的,经过反编译工具是可以还原回来的。例如Decafe、FrontEnd,YingJAD和Jode等等软件。下面是《Nokia中Short数组转换算法》
类中Main函数的ByteCode:0 ldc #162 invokestatic #185 astore_16 return其源代码是:short [] pixels = parseImage("/ef1s.png");
我们通过反编译工具是可以还原出以上源代码的。而通过简单的分析,我们也能自己写出源代码的。
第一行:ldc #16
ldc为虚拟机的指令,作用是:压入常量池的项,形式如下ldc index这个index就是上面的16,也就是在常量池中的有效索引,当我们去看常量池的时候,我们就会找到index为16的值为String_info,里面存了/ef1s.png.
所以这行的意思就是把/ef1s.pn作为一个String存在常量池中,其有效索引为16。
第二行:2 invokestatic #18
invokestatic为虚拟机指令,作用是:调用类(static)方法,形式如下
invokestatic indexbyte1 indexbyte2
其中indexbyte1和indexbyte2必须是在常量池中的有效索引,而是指向的类型必须有Methodref标记,对类名,方法名和方法的描述符的引用。
所以当我们看常量池中索引为18的地方,我们就会得到以下信息:
Class Name : cp_info#1
Name Type : cp_info#19
1 和19都是常量池中的有效索引,值就是右边<中的值,再往下跟踪我就不多说了,有兴趣的朋友可以去JAVA虚拟机规范。
这里我简单介绍一下parseImage(Ljava/lang/String;)[S 的意思。
这就是parseImage这个函数的运行,我们反过来看看parseImage的原型就明白了
short [] parseImage(String)
那么Ljava/lang/String;就是说需要传入一个String对象,而为什么前面要有一个L呢,这是JAVA虚拟机用来表示这是一个Object。如果是基本类型,这里就不需要有L了。然后返回为short的一维数组,也就是对应的[S。是不是很有意思,S对应着Short类型,而“[”对应一维数组,那有些朋友要问了,两维呢,那就“[[”,呵呵,是不是很有意思。
好了,调用了函数,返回的值要保存下来吧。那么就是第三行要做的事情了。
G. c语言定义常量为什么不建议用#define
1、尽量用const和inline而不用#define
这个条款最好称为:“尽量用编译器而不用预处理”,因为#define经常被认为好象不是语言本身的一部分。这是问题之一。
2、再看下面的语句:
#define ASPECT_RATIO 1.653
编译器会永远也看不到ASPECT_RATIO这个符号名,因为在源码进入编译器之前,它会被预处理程序去掉,于是ASPECT_RATIO不会加入到符号列表中。如果涉及到这个常量的代码在编译时报错,就会很令人费解,因为报错信息指的是1.653,而不是ASPECT_RATIO。如果ASPECT_RATIO不是在你自己写的头文件中定义的,就会奇怪1.653是从哪里来的,甚至会花时间跟踪下去。这个问题也会出现在符号调试器中,因为同样所写的符号名不会出现在符号列表中。
解决这个问题的方案很简单:不用预处理宏,定义一个常量:
const double ASPECT_RATIO = 1.653;
这种方法很有效。但有两个特殊情况要注意。
首先,定义指针常量时会有点不同。因为常量定义一般是放在头文件中(许多源文件会包含它),除了指针所指的类型要定义成const外,重要的是指针也经常要定义成const。例如,要在头文件中定义一个基于char*的字符串常量,要写两次const:
const char * const authorName = "Scott Meyers ";