else//当X不小于Y时再作判断
{
if(x==y)
printf("X=Y\n");//当X等于Y时
else
printf("X>Y\n");//当X大于Y时
}
}
}
要注意的是,在连接PC串口调试时。
发送数字时,发送完一个数字后还要发送一个回车符,以使scanf函数确认有数据输入。
Printf,scanf函数的具体用法,将和其它相关函数集中出现在的C51函数详解中,敬请大家留意。
逻辑运算符
关系运算符所能反映的是两个表达式之间的大小等于关系,那逻辑运算符则是用于求条件式的逻辑值,用逻辑运算符将关系表达式或逻辑量连接起来就是逻辑表达式了。
也许你会对为什?
quot;逻辑运算符将关系表达式连接起来就是逻辑表达式了"这一个描述有疑惑的地方。
其实之前说过"要注意的是用关系运算符的运算结果只有0和1两种,也就是逻辑的真与假",换句话说也就是逻辑量,而逻辑运算符就用于对逻辑量运算的表达。
至于复杂的逻辑量的运算法则我也知之甚少,如要了解的朋友可以参看数字电路的教科书、逻辑学或数学书,而之里只能说说简单常用的几种。
逻辑表达式的一般形式为:
逻辑与:
条件式1&&条件式2
逻辑或:
条件式1||条件式2
逻辑非:
!
条件式2
图7-5 演示结果
逻辑与,说白了就是当条件式1"与"条件式2都为真时结果为真(非0值),否则为假(0值)。
也就是说运算会先对条件式1进行判断,如果为真(非0值),则继续对条件式2进行判断,当结果为真时,逻辑运算的结果为真(值为1),如果结果不为真时,逻辑运算的结果为假(0值)。
如果在判断条件式1时就不为真的话,就不用再判断条件式2了,而直接给出运算结果为假。
逻辑或,是指只要二个运算条件中有一个为真时,运算结果就为真,只有当条件式都不为真时,逻辑运算结果才为假。
逻辑非则是把逻辑运算结果值取反,也就是说如果两个条件式的运算值为真,进行逻辑非运算后则结果变为假,条件式运算值为假时最后逻辑结果为真。
同样逻辑运算符也有优先级别,!
(逻辑非)→&&(逻辑与)→||(逻辑或),逻辑非的优先值最高。
如有 !
True||False&&True
按逻辑运算的优先级别来分析则得到(True代表真,False代表假)
!
True||False&&True
False||False&&True//!
Ture先运算得False
False||False//False&&True运算得False
False//最终False||False得False
下面我们来用程序语言去有表达,如下:
#include
#include
voidmain(void)
{
unsignedcharTrue=1;//定义
unsignedcharFalse=0;
SCON=0x50;//串口方式1,允许接收
TMOD=0x20;//定时器1定时方式2
TH1=0xE8;//11.0592MHz1200波特率
TL1=0xE8;
TI=1;
TR1=1;//启动定时器
if(!
True||False&&True)
printf("True\n");//当结果为真时
else
printf("False\n");//结果为假时
}
大家可以使用以往学习的方法用keil或烧到片子上用串口调试。
可以更改"!
True||False&&True"这个条件式,以实验不同算法组合来掌握逻辑运算符的使用方法。
第七课 运算符和表达式(3)
位运算符
学过汇编的朋友都知道汇编对位的处理能力是很强的,但是C语言也能对运算对象进行按位操作,从而使C语言也能具有一定的对硬件直接进行操作的能力。
位运算符的作用是按位对变量进行运算,但是并不改变参与运算的变量的值。
如果要求按位改变变量的值,则要利用相应的赋值运算。
还有就是位运算符是不能用来对浮点型数据进行操作的。
C51中共有6种位运算符。
位运算一般的表达形式如下:
变量1位运算符变量2
位运算符也有优先级,从高到低依次是:
"~"(按位取反)→"<<"(左移)→">>"(右移)→"&"(按位与)→"^"(按位异或)→"|"(按位或)
表7-1是位逻辑运算符的真值表,X表示变量1,Y表示变量2
X
Y
~X
~Y
X&Y
X|Y
X^Y
0
0
1
1
0
0
0
0
1
1
0
0
1
1
1
0
0
1
0
1
1
1
1
0
0
1
1
0
表7-1 按位取反,与,或和异或的逻辑真值表
利用以前建立起来的实验板,我们来做个实验验证一下位运算是否真是不改变参与变量的值,同时学习位运算的表达形式。
程序很简单,用P1口做运算变量,P1.0-P1.7对应P1变量的最低位到最高位,通过连接在P1口上的LED我们便可以直观看到每个位运算后变量是否有改变或如何改变。
程序如下:
#include
voidmain(void)
{
unsignedinta;
unsignedintb;
unsignedchartemp;//临时变量
P1=0xAA;//点亮D1,D3,D5,D7P1口的二进制为10101010,为0时点亮LED
for(a=0;a<1000;a++)
for(b=0;b<1000;b++);//延时
temp=P1&0x7;//单纯的写P1|0x7是没有意义的,因为没有变量被影响,不会被编译
//执行P1|0x7后结果存入temp,这时改变的是temp,但P1不会被影响。
//这时LED没有变化,仍然是D1,D3,D5,D7亮
for(a=0;a<1000;a++)
for(b=0;b<1000;b++);//延时
P1=0xFF;//熄灭LED
for(a=0;a<1000;a++)
for(b=0;b<1000;b++);//延时
P1=0xAA;//点亮D1,D3,D5,D7P1口的二进制为10101010,为0时点亮LED
for(a=0;a<1000;a++)
for(b=0;b<1000;b++);//延时
P1=P1&0x7;//这时LED会变得只有D2灭
//因为之前P1=0xAA=10101010
//与0x7位与0x7=00000111
//结果存入P1P1=00000010//位为O时点亮LED,电路看第三课
for(a=0;a<1000;a++)
for(b=0;b<1000;b++);//延时
P1=0xFF;//熄灭LED
while
(1);
//大家可以根据上面的程序去做位或,左移,取反等等。
}
复合赋值运算符
复合赋值运算符就是在赋值运算符"="的前面加上其他运算符。
以下是C语言中的复合赋值运算符:
+= 加法赋值 >>= 右移位赋值
-= 减法赋值 &= 逻辑与赋值
*= 乘法赋值 |= 逻辑或赋值
/=除法赋值 ^= 逻辑异或赋值
%= 取模赋值 -= 逻辑非赋值
<<=左移位赋值
复合运算的一般形式为:
变量 复合赋值运算符 表达式
其含义就是变量与表达式先进行运算符所要求的运算,再把运算结果赋值给参与运算的变量。
其实这是C语言中一种简化程序的一种方法,凡是二目运算都可以用复合赋值运算符去简化表达。
例如:
a+=56等价于a=a+56
y/=x+9等价于y=y/(x+9)
很明显采用复合赋值运算符会降低程序的可读性,但这样却可以使程序代码简单化,并能提高编译的效率。
对于初学C语言的朋友在编程时最好还是根据自己的理解力和习惯去使用程序表达的方式,不要一味追求程序代码的短小。
逗号运算符
如果你有编程的经验,那么对逗号的作用也不会陌生了。
如在VB中"Dima,b,c"的逗号就是把多个变量定义为同一类型的变量,在C也一样,如"inta,b,c",这些例子说明逗号用于分隔表达式用。
但在C语言中逗号还是一种特殊的运算符,也就是逗号运算符,可以用它将两个或多个表达式连接起来,形成逗号表达式。
逗号表达式的一般形式为:
表达式1,表达式2,表达式3……表达式n
这样用逗号运算符组成的表达式在程序运行时,是从左到右计算出各个表达式的值,而整个用逗号运算符组成的表达式的值等于最右边表达式的值,就是"表达式n"的值。
在实际的应用中,大部分情况下,使用逗号表达式的目的只是为了分别得到名个表达式的值,而并不一定要得到和使用整个逗号表达式的值。
要注意的还有,并不是在程序的任何位置出现的逗号,都可以认为是逗号运算符。
如函数中的参数,同类型变量的定义中的逗号只是用来间隔之用而不是逗号运算符。
条件运算符
上面我们说过C语言中有一个三目运算符,它就是"?
:
"条件运算符,它要求有三个运算对象。
它可以把三个表达式连接构成一个条件表达式。
条件表达式的一般形式如下:
逻辑表达式?
表达式1:
表达式2
条件运算符的作用简单来说就是根据逻辑表达式的值选择使用表达式的值。
当逻辑表达式的值为真时(非0值)时,整个表达式的值为表达式1的值;当逻辑表达式的值为假(值为0)时,整个表达式的值为表达式2的值。
要注意的是条件表达式中逻辑表达式的类型可以与表达式1和表达式2的类型不一样。
下面是一个逻辑表达式的例子。
如有a=1,b=2这时我们要求是取ab两数中的较小的值放入min变量中,也许你会这样写:
if(a
min=a;
else
min=b;//这一段的意思是当a
用条件运算符去构成条件表达式就变得简单明了了:
min=(a
a:
b
很明显它的结果和含意都和上面的一段程序是一样的,但是代码却比上一段程序少很多,编译的效率也相对要高,但有着和复合赋值表达式一样的缺点就是可读性相对效差。
在实际应用时根据自己要习惯使用,就我自己来说我喜欢使用较为好读的方式和加上适当的注解,这样可以有助于程序的调试和编写,也便于日后的修改读写。
指针和地址运算符
在第四课我们学习数据类型时,学习过指针类型,知道它是一种存放指向另一个数据的地址的变量类型。
指针是C语言中一个十分重要的概念,也是学习C语言中的一个难点。
对于指针将会在第九课中做详细的讲解。
在这里我们先来了解一下C语言中提供的两个专门用于指针和地址的运算符:
* 取内容
& 取地址
取内容和地址的一般形式分别为:
变量=*指针变量
指针变量=&目标变量
取内容运算是将指针变量所指向的目标变量的值赋给左边的变量;取地址运算是将目标变量的地址赋给左边的变量。
要注意的是:
指针变量中只能存放地址(也就是指针型数据),一般情况下不要将非指针类型的数据赋值给一个指针变量。
下面来看一个例子,并用一个图表和实例去简单理解指针的用法和含义。
设有两个unsignedint变量 ABC处CBA存放在0x0028,0x002A中
另有一个指针变量 portA存放在0x002C中
那么我们写这样一段程序去看看*,&的运算结果
unsignedintdataABC_at_0x0028;
unsignedintdataCBA_at_0x002A;
unsignedintdata*Port_at_0x002C;
#include
#include
voidmain(void)
{
SCON=0x50;//串口方式1,允许接收
TMOD=0x20;//定时器1定时方式2
TH1=0xE8;//11.0592MHz1200波特率
TL1=0xE8;
TI=1;
TR1=1;//启动定时器
ABC=10;//设初值
CBA=20;
Port=&CBA;//取CBA的地址放到指针变量Port
*Port=100;//更改指针变量Port所指向的地址的内容
printf("1:
CBA=%d\n",CBA);//显示此时CBA的值
Port=&ABC;//取ABC的地址放到指针变量Port
CBA=*Port;//把当前Port所指的地址的内容赋给变量CBA
printf("2:
CBA=%d\n",CBA);//显示此时CBA的值
printf("ABC=%d\n",ABC);//显示ABC的值
}
程序初始时
值
地址
说明
0x00
0x002DH
0x00
0x002CH
0x00
0x002BH
0x00
0x002AH
0x0A
0x0029H
0x00
0x0028H
执行ABC=10;向ABC所指的地址0x28H写入10(0xA),因ABC是int类型要占用0x28H和0x29H两个字节的内存空间,低位字节会放入高地址中,所以0x28H中放入0x00,0x29H中放入0x0A
值
地址
说明
0x00
0x002DH
0x00
0x002CH
0x00
0x002BH
0x00
0x002AH
0x0A
0x0029H
ABC为int类型占用两字节
0x00
0x0028H
执行CBA=20;原理和上一句一样
值
地址
说明
0x00
0x002DH
0x00
0x002CH
0x14
0x002BH
CBA为int类型占用两字节
0x00
0x002AH
0x0A
0x0029H
ABC为int类型占用两字节
0x00
0x0028H
执行Port=&CBA;取CBA的首地址放到指针变量Port
值
地址
说明
0x00
0x002DH
0x2A
0x002CH
CBA的首地址存入Port
0x14
0x002BH
0x00
0x002AH
0x0A