int(a+ b)和int(a)有啥区别

a++与++a 首先在java中a++和++a都属于自增运算符 关于区别我们来看下边程序: public static void main(String[] args) {
int a = 0;
System.out.println("初始化a:"+a);
int b = a++;
System.out.println("a++运算:"+b);
System.out.println("a++运算结束,a值:"+a);
a = 0;
System.out.println("初始化a:"+a);
int c = ++a;
System.out.println("++a运算:"+c);
System.out.println("++a运算结束,a值:"+a);
}
我们将a++赋值给b,将++a赋值给c,方便打印程序输出结果:
初始化a:0
a++运算:0
a++运算结束,a值:1
初始化a:0
++a运算:1
++a运算结束,a值:1
从输出结果可以看出:
a++运算输出为0,但是经过a++后,a的值最终为1++a运算输出为1,经过a++后,a的值最终为1所以可以得出:
a++是先进行取值,然后进行自增运算.
++a是先进行自增运算,然后进行取值.
为知其然知其所以然,我们使用IDEA打开对应的ByteCode
public static main([Ljava/lang/String;)V
L0
LINENUMBER 10 L0
ICONST_0
ISTORE 1
L1
LINENUMBER 11 L1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ILOAD 1
IINC 1 1
INVOKEVIRTUAL java/io/PrintStream.println (I)V
L2
LINENUMBER 12 L2
ICONST_0
ISTORE 1
L3
LINENUMBER 13 L3
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
IINC 1 1
ILOAD 1
INVOKEVIRTUAL java/io/PrintStream.println (I)V
L4
LINENUMBER 24 L4
RETURN
L5
LOCALVARIABLE args [Ljava/lang/String; L0 L5 0
LOCALVARIABLE a I L1 L5 1
MAXSTACK = 2
MAXLOCALS = 2
大致来说:L0是初始化变量a为0,L1体现的是a++时的操作;L2将a的值再次初始化为0,L3为++a时的操作从对应的字节码中我们可以观察到几个关键的指令:
ICONST_0 : 将常量 0 压入操作数栈中ISTORE 1 : 弹出操作数栈栈顶元素,保存到局部变量表第1个位置ILOAD 1 :第1个变量压入操作数栈IINC 1 1 : 局部变量表中的第1位的变量a执行自增操作从对应的字节码可以看出:
恍然大悟.与上方我们用程序得出的结果相匹配
}
在说这个问题之前,先说两个需要知道的背景知识:(1)语言的类型的强制转换不会修改原来的数据,会另外的开辟一个临时的或者程序中指定的空间来存储强制转换后的值。(2)C++引用的实现是在符号表中动了手脚,把自己的变量符号对应的内存地址写成了它所引用的那个变量的内存地址了。(3)C++的cout函数的执行,是根据变量的名称找到对应的内存地址,然后根据变量的类型从内存中抓取相应的数据。有了上面的两个知识点,看下面的程序:#include <iostream>
using namespace std;
int main()
{
float a = 1.0f;
cout << (int)a << endl;
cout << (int &)a << endl;
cout << endl;
float b = 0.0f;
cout << (int)b << endl;
cout << (int &)b << endl;
return 0;
}
  程序执行结果:首先先来看(int&)a是什么意思:这句话的意思就是给a声明了一个匿名的引用,并且这个引用是临时的,int类型的。会再符号表中增加这么一个条目(int&)a这个表达式就返回这个临时的变量temp,它是a的引用,只不过类型是int的。所以在执行cout << (int &)a << endl;这句话的时候,cout就根据temp的地址和类型抓取数据。看完了(int&)a,那么(int)a呢?似乎很熟悉,但是真的知道具体的过程吗。也许吧,看下面:前面说到,对数据的类型强制转换,不会修改原来的数据的内容。所以(int)a这个表达式会再符号表中产生这样一个条目:看到了,这里的临时变量的内存地址不是原来的地址,是操作系统又重新分配了一块临时的内存地址。这块内存地址的值就是变量类型强制转换后的值。这样可以看出来这两个语句一个是在原来的内存基础上,把float类型的数据以int输出,一个是强制转转数据类型,从新开辟了一块新的存储空间放转换后的值,然后再输出。上面分析的是程序的原理,应该是这么实现的。但是编译器为了减少访问内存的次数(符号表也在内存中的哦~),经常用寄存器来处理这些临时的变量,看这个程序的汇编代码:--- C:\Program Files\Microsoft Visual Studio\MyProjects\TestThread\testThread.cpp
-----------------------------------------------------------------
1:
#include <iostream>
2:
using namespace std;
3:
4:
int main()
5:
{
00401780
push
ebp
00401781
mov
ebp,esp
00401783
sub
esp,48h
00401786
push
ebx
00401787
push
esi
00401788
push
edi
00401789
lea
edi,[ebp-48h]
0040178C
mov
ecx,12h
00401791
mov
eax,0CCCCCCCCh
00401796
rep stos
dword ptr [edi]
6:
float a = 1.0f;
00401798
mov
dword ptr [ebp-4],3F800000h//这里看到,1.0在内存中的存储方式,是单精度浮点数的存储方式
7:
cout << (int)a << endl;
0040179F
push
offset @ILT+195(std::endl) (004010c8)
004017A4
fld
dword ptr [ebp-4]//把这个内存单元中的数据以浮点数方式加载到浮点寄存器中
004017A7
call
__ftol (0042133c)//这个函数就把浮点数寄存器中的数据转换成了int类型,并把结果放在了eax寄存器中。转换完之后的结果00000001h
004017AC
push
eax//输出eax中的数据
004017AD
mov
ecx,offset std::cout (0047ff88)
004017B2
call
@ILT+245(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010fa)//ILT是Debug模式下函数的入口表,Release下就直接调用函数了,245是int类型数据的输出函数序号
004017B7
mov
ecx,eax
004017B9
call
@ILT+470(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011db)
8:
cout << (int &)a << endl;
004017BE
push
offset @ILT+195(std::endl) (004010c8)
004017C3
mov
eax,dword ptr [ebp-4]//直接把a的值原封不动的copy到eax寄存去中
004017C6
push
eax//输出eax中的数据
004017C7
mov
ecx,offset std::cout (0047ff88)
004017CC
call
@ILT+245(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010fa)
004017D1
mov
ecx,eax
004017D3
call
@ILT+470(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011db)
9:
cout << a << endl;
004017D8
push
offset @ILT+195(std::endl) (004010c8)
004017DD
mov
ecx,dword ptr [ebp-4]
004017E0
push
ecx
004017E1
mov
ecx,offset std::cout (0047ff88)
004017E6
call
@ILT+285(std::basic_ostream<char,std::char_traits<char> >::operator<<) (00401122)//285是float类型数据的输出函数序号
004017EB
mov
ecx,eax
004017ED
call
@ILT+470(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011db)
10:
11:
cout << endl << endl;
004017F2
push
offset @ILT+195(std::endl) (004010c8)
004017F7
push
offset @ILT+195(std::endl) (004010c8)
004017FC
mov
ecx,offset std::cout (0047ff88)
00401801
call
@ILT+470(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011db)
00401806
mov
ecx,eax
00401808
call
@ILT+470(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011db)
12:
13:
float b = 0.0f;
0040180D
mov
dword ptr [ebp-8],0
14:
cout << (int)b << endl;
00401814
push
offset @ILT+195(std::endl) (004010c8)
00401819
fld
dword ptr [ebp-8]
0040181C
call
__ftol (0042133c)
00401821
push
eax
00401822
mov
ecx,offset std::cout (0047ff88)
00401827
call
@ILT+245(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010fa)
0040182C
mov
ecx,eax
0040182E
call
@ILT+470(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011db)
15:
cout << (int &)b << endl;
00401833
push
offset @ILT+195(std::endl) (004010c8)
00401838
mov
edx,dword ptr [ebp-8]
0040183B
push
edx
0040183C
mov
ecx,offset std::cout (0047ff88)
00401841
call
@ILT+245(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010fa)
00401846
mov
ecx,eax
00401848
call
@ILT+470(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011db)
16:
17:
return 0;
0040184D
xor
eax,eax
18:
}
View Code从汇编语言中看到,(int)a是要经过类型强制转换的,并且把转换后的值放在寄存器中输出,(int&)a直接把原来的数据copy到一个寄存器中输出。重要的说明一下:符号表是在编译阶段产生的,上面说的temp和temp1这样的临时的变量也是在编译的时候都已经弄到了符号表中,只不过它 的作用域仅仅的就是那句话。不是在执行阶段在往符号表中增加的条目。最后再说一个知识点:单精度浮点数、双精度浮点数的存储。单精度和双精度浮点数的存储方式和int类型的存储方式是完全不同的,int的1在内存中的存储方式是00000001h,int的0是00000000h,但是浮点数要用符号位+阶码+尾数的方式存储。以单精度的float为例:它的形式是1.M * 2E-127,其中E是指数为的移码形式。所以对于float的1.0,尾数M=0,阶码E=127,符号位是0,所以对应的机器码是:3F800000h。提示:为什么浮点数阶码部分要用移码?(1)使用移码方便运算。2的指数部分有正有负,使用了移码之后,2的指数依然有正有负,但是数据的真正的存储位E就完全是正的值了,没有了负值,这样能加快运算。(2)为了统一浮点数的0和整数的0。整数0的各个二进制位是全0(公认的了),但是如果不用移码,浮点数的全0是1,用了移码之后,这个是就是1.0 * 20-127,由于这个数太小了,这时会发生溢出,也就是0。}
本卷共有3道大题:一、单项选择题(50道小题,共50分)1、下列计算机语言中,CPU能直接执行的是( D )。(1分) A、自然语言 B、高级语言 C、汇编语言 D、机器语言2、算法具有5个特性,以下选项中不属于算法特性的是( B )。(1分) A、有穷性 B、简洁性 C、可行性 D、确定性3、以下叙述中,正确的叙述是( A )。(1分)A、构成C程序的基本单位是函数 B、可以在一个函数中定义另一个函数C、main( )函数必须放在其他函数之前 D、所有被调用的函数一定要在调用之前进行定义4、已知字母A的ASCII码为十进制的65,char ch1,ch2;ch1='A'+'5'-'3';ch2='A'+'6'-'3';,则printf(\的输出是( A )。(1分) A、67,D B、B,CC、C,D D、不确定的值5、c2为字符型,执行语句“c2='A'+'6'-'3';”后,c2的值为(A )。(1分) A、D B、63 C、不确定的值 D、C6、若a为int类型,且其值为5,则执行完表达式a+=a-=a*a后,a的值是( C )。(1分) A、-5 B、20 C、-40 D、257、设a、b和c都是int型变量,且a=3,b=4,c=5,则下面的表达式中,值为0的表达式是( D )。(1分) A、'a'&&'b' B、a<=bC、a
b+c&&b-c D、!((a<b)&&!c
1)8、表达式18/4*sqrt(4.0)/8值的数据类型为( C )。(1分) A、int B、float C、double D、不确定9、设x是int型变量,f是float型变量,用下面的语句给这两个变量输入值:scanf(\\,为了把100和765.12分别送给i和f,正确的输入为(B )。(1分)A、100 B、i=100,f=765.12C、100 D、x=100f=765.1210、下列表述中,合法的C语言赋值语句是( B )。(1分) A、a=b=58 B、i++;C、a=58, b=58 D、k=int(a+b); 11、若k是int型变量,程序片段 k=-3; if(k<=0) printf(\printf(\的输出结果是( A )。(1分) A、#### B、&&&&C、####&&&& D、有语法错误,无输出结果 12、程序main(){int x=1, y=0, a=0, b=0;switch(x){case 1: switch(y) {case 0: a++;break; case 1: b++;break; } case 2: a++; b++; break;}printf(\的输出结果是( A )。 (1分) A、a=2, b=1 B、a=1, b=1 C、a=1, b=0 D、a=2, b=213、若有定义float w; int a, b; ,则合法的switch语句是( C )。(1分) A、switch(w) { case 1.0: printf(\B、switch(a); { case 1 printf(\C、switch(b) { case 1: printf(\default: printf(\case 1+2: printf(\D、switch(a+b); { case 1: printf(\printf(\14、若有int a[4][5];,则数组a包含的元素个数是( D )。(1分) A、4 B、5 C、9 D、2015、下列语句中,正确的定义语句是( B )。(1分) A、int A[a]; B、int A[10]; C、int A[3,4]; D、int A[][3]16、下列描述中,能正确给字符数组str定义和赋值的是( A )。(1分) A、char str[]={\ B、char str[10];str={\C、char str[10]={\D、char str[10];strcpy(str,\17、若有char c[6]={'H','e','l','l','o'};,则c[5]的值是( B )。(1分) A、'0' B、'\\0'C、空格 D、不可知的18、设有定义:char c,string[]=\zhanghong\,若要逐个输出元素的值,可以写一个循环程序段,则这个循环段的“循环条件”是( D )。(1分) A、c=string[i]='\\0' B、(c=string[i])='\\0' C、c=string[i]!='\\0' D、(c=string[i])!='\\0'19、在Turbo C下,若有数组定义:float f[10]={1,2,3,4};,则数组f所占的存储空间为( D )个字节。(1分) A、4 B、16 C、10 D、4020、C语言允许用外部说明来指定变量、函数等,这里的外部指的是( D )。(1分) A、冠以关键字extern B、位置在函数体外部 C、作用范围是全程的 D、位置在函数外部21、下列关于静态局部变量的说法中,不正确的说法是( D )。(1分) A、静态局部变量在函数内定义 B、静态局部变量的生存期为整个源程序C、静态局部变量的作用域为整个源程序 D、静态局部变量若在说明时未赋初值,则系统自动赋予0值22、下列关于局部变量的说法中,不正确的说法是( A )。(1分) A、不能在复合语句中定义变量 B、局部变量是在函数内部定义说明的C、形参变量属于被调函数的局部变量 D、允许在不同的函数中使用相同的变量名23、在复合语句中定义的变量( B )。(1分) A、只在主函数中有效 B、只在本复合语句中有效 C、可以在整个文件中有效 D、可以在所有函数中有效24、如果全局的外部变量和函数体内定义的局部变量重名,则(B )。(1分) A、出错 B、局部变量优先C、外部变量优先 D、全局的外部变量优先25、在主函数中定义的变量( A )。(1分) A、只在主函数中有效 B、可以在整个文件中有效C、可以在所有函数中有效 D、可以在被调用的函数中有效26、能够在输出完字符串后自动输出一个回车换行的函数是( B )函数。(1分) A、putc() B、puts()C、printf() D、putchar()27、在C程序中,main()的位置( A)。(1分) A、可以任意 B、必须作为第一个函数C、必须作为最后一个函数 D、必须放在它所调用的函数之后28、如果函数值的类型和return语句中表达式的值不一致,则(C )。(1分) A、语法出错 B、连接出错C、以函数类型为准 D、以表达式值的类型为准29、若在程序中用到“strlen()”函数时,应在程序开头写上(D )。(1分) A、#includeB、#includeC、#includeD、#include30、若有int f(int a,int b);,则说明函数f( B )。(1分) A、是一个内部函数 B、是一个外部函数C、只能在本文件中使用 D、不能被同一源程序其他本文件中的函数调用31、声明一个函数为外部函数,应该在声明函数的函数类型的前面加(C )。(1分) A、auto B、static C、extern D、register32、若有int a=3,*pa; float f=4.5,*pf;,则下列表述中,错误的是 (B )。(1分) A、pa=&a B、pa=&f C、pf=&f D、*pf=a+f33、设char s[10];int i=5;,下列表达式中,正确的表达式是( B )。(1分) A、s[i+6] B、*(s+i) C、*(&s+i) D、*((s++)+i34、若有int a[10],*p=a;,则( C )。(1分)A、p++可以使p指向下一个字节 B、p+=2 相当于p=sizeof(a)/10C、p++可以使p指向下一个元素,即a[1]的首地址 D、p+=2可以使p指向下一个元素,即a[1]的首地址35、设有语句:int a[10]={0,1,2,3,4,5,6,7,8,9},i,*p=a;,下列表达式中,对a数组元素引用错误的是( D )。(1分) A、p[i] B、a[p-a]C、*(&a[i]) D、*(*a(a+i))36、在C语句中,&后跟指针变量名,表示该指针变量的((C )。(1分) A、值 B、别名 C、地址 D、类型37、若程序中包含有以下说明和定义:struct ex{ int x,y;} ? struct ex,x,y; ? ,则在计算机上调试时, ( A )。(1分) A、编译出错 B、可以编译、连接、执行C、可以编译、连接,但不能执行 D、可以编译,但连接出错 38、“.”运算符称为( C )运算符。(1分) A、指针 B、取地址C、结构体成员 D、指向结构体成员39、设有定义语句“struct {int a;float b;char c;}abc;”,则对结构体成员a的引用可以是( A )。(1分) A、abc.a B、abc-a}

我要回帖

更多关于 int*p=&amp;a和*p=a 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信