十一.逻辑运算符使用分析
&&和||的短路规则:||从左向右计算,遇到为真的条件时停止计算,整个表达式为真;所有条件为假时,表达式才为假
&&从左向右计算,当遇到为假的条件时停止计算,整个表达式为假;所有条件为真时表达式才为真。
!运算符的结果只有0和1,只有作用0时才为1,作用不为零时结果是0.
三目运算符(a?b:c)可以作为逻辑运算符的载体。
十二.位运算符:&,|,^,~,<<,>>
位运算符优先级比数学运算符优先级别低,所以同时参与运算的时候,尽量使用括号来表达计算次序:
例如:0x1<<2+3,运算的结果就是0x1<<(2+3),不是我们想要的结果,应该这样写:(0x1<<2)+3
异或^运算符可以用来交换两个变量,利用两个相同变量异或为0,变量和0异或等于他自己本身的规则
十三.++,--操作符
int i = 3;
(++i) + (++i) + (++i) = ?
结果有两个16或者18,编译器有两个解析方式,第一个是认为括号里面的优先级最高所以先把括号里面的运算完成,结果i=6.
然后6+6+6=18,另一种是先计算前两个括号相加,i经过两次++,=5所以最后结果是5+5+6=16,例如gcc,g++。
这是和编译器的方式有关系的,尽量不要这样写代码
使用逗号运算符,可以使++运算符按照顺序来,不会被编译器优化掉
int x;
int i = 3;
x = (++i,i++,i+10);
编译器的贪心法读取:编译器处理的每个字符应该尽可能多的包含字符
编译器以从左到右的顺序一个一个尽可能多的读入字符
当读入的字符不可能和已读入的字符组成合法符号为止
int i=0;int j = ++i+++i+++i;====》++i++ + i++ +i,所以编译器会报错,因为++0++是错误的
b = b/*p ,因为编译器解析成为:b = b /*p,/*后面解析成为注释,加上空格就可以正确,b=b / *p
a+++b ====> a++ + b合法
结束贪心法的方法:使用空格或者分号可以告诉编译器不要贪心,所以多使用空格有好处
十四. 优先级和类型转换符
容易出错的优先级:
#include <stdio.h>
#include <malloc.h>
typedef struct _demo
{
int* pInt;
float f;
} Demo;
int func(int v, int m)
{
return (v & m != 0);
}
int main()
{
Demo* pD = (Demo*)malloc(sizeof(Demo));
int *p[5];
int *f();
int i = 0;
i = 1, 2;
*pD.f = 0;
free(pD);
return 0;
}
编译会报错。解析:根据优先级表,int *p[5],int *f(),i=1,2都不能得到我们想要的结果,这样的写法能够看得清晰很多:int* p[5],int* f().(注:要利用好空格)。编译器报错会在*pD.f = 0;因为编译器会解析成为*(pD.f)
C语言隐式类型转换:
#include <stdio.h>
int main()
{
char c = 'c';
short s = 0;
s= c;
printf("%d\n",sizeof(s+c));
}
打印结果:4
解析:char和short相加,隐式转换成为int,4个字节(char是一个字节,short是两个字节)
#include <stdio.h>
int main()
{
int i = -2;
unsigned int j = 1;
if( (i + j) >= 0 )
{
printf("i+j>=0\n");
}
else
{
printf("i+j<0\n");
}
printf("i+j=%d\n", i + j);
return 0;
}
打印结果:i+j>0,i+j=-1;
解析:因为int型的i和unsigned int型的j相加,类型自动升级为unsigned int,所以i+j=-1转成整型数就是0xffffffff,所以肯定大于0,最后printf打印的时候,使用的是
%d格式,这是一个int型的格式,所以可以正常打印-1,如果使用%ud就会打印出很大的整数,使用%x就会打印十六进制数0xffffffff