最近组织了网上的朋友们一起在读《C和指针》这本书。如果想要加入的可以加入我们:213867076,群里主要是玩STM32单片机和嵌入式方面的,进群验证就写C和指针把。
第五章有好多的干货,把一些我之前不太熟悉或者我觉的有必要记住的记录下来。
1、数据截短。在第70页中讲到由于数据类型的不同,会导致数据截短。下面是例子:
char x;
int a ;
int y = 1000;
x = a = y + 3;
可以看到,由于 x 是char类型,所以将EAX的值传给CL时(给 x 赋值时我这编译器用的CX寄存器),
自动将0x03eb截成了0xeb。所以运行后,a= 1003 而x=235(0xeb)。
2、还是数据截短。书上的例子
char ch;
while((ch = getch() ) != EOF
{
//执行相应任务
}
这里面有一个问题,getchar()函数返回值是int类型,返回的是用户输入字符对应的ASCⅡ码值。getchar()的返回值存储于ch中将导致它被截短。然后这个被截短的值被提升为整型并与EOF比较。
标准ASCⅡ码只到127。值128到255对应的ASCⅡ码在它的扩展表中。好像我们普通的计算机敲不出这样的字符来。
所以虽然char在这里算是有符号字符集,但是还是会永不停止的循环,除非我按ctrl+z。
3、if语句的条件语句。程序中经常遇到这样的代码
x = get_some_value();
if(x = 1)
{
//执行相应任务
}
x从函数获得一个值,但接下来把1赋值给x,而不是把x与字面值1比较,从而丢失了从函数获得的那个值。
这个意图显然不是程序员的意图所在。另外一个问题是x获得了新值,所以if语句一直为真。
有一种更好的方式,让编译器来帮助我们检查这一疏忽。写成如下方式
x = get_some_value();
if(1 == x)
{
//执行相应任务
}
这样,如果写成if(1 = x)的话,编译器就会告诉你这里少写了个等号。
4、隐式类型转换。这个小的知识点是以前不知道的
下面这段话是从书上抄下来的,在书的P80页:
C的整形运算总是至少以缺省整型类型的精度来进行的。为了获得这个精度,
表达式中的字符型和短整型操作数在使用之前会被转换成普通整型,这种转换称为整型提升。
例如下面的表达式:
char a,b,c
a = b + c;
b和c的值被提升为普通整型,然后再执行加法运算。加法运算的结果会被截短,然后再存储于a中。让我们测试一下:
观察反汇编代码,可以看到在做加法的时候,用的是32位寄存器:EAX = EAX + ECX。
做完加法赋值的时候,按照char类型的长度8位,只将 EAX 寄存器的 AL 部分赋值给了a。
5、类似于a+b+c这样的语句,编译器自由决定以任何顺序对表达式求值。(这部分是书上的,在P84页)
之所以允许先计算b+c是因为这个值可能可以从前面的一些表达式中获得,所以直接复用这个值比重新求值效率更高。
下面的表达式说明了一个相关的问题:
f() + g() + h()
尽管左边那个加法运算必须在右边那个加法运算之前执行,但对于各个函数的调用顺序,并没有规则加以限制。
如果他们的执行具有副作用,比如执行一些I/O任务或修改全局变量,那么函数调用顺序的不同可能会产生不同的效果。
因此,如果顺序会导致结果产生区别,最好使用临时变量,让每个函数调用都在单独的语句中执行。
temp = f();
temp += g();
temp += h();
对指定的位 置1 value =value | 1<< n
对指定的位 置0 value = value & ~(1<< n)
对指定位测试,若是1,则表达式结果非0 value & 1 << n 。 注意 这里的n是从0开始算的。0就是不移位。1往左移1位