"C陷阱和缺陷"中的几个知识点

1.词法分析中的“贪心法”

C语言中的某些符号,例如/、*、和=,只有一个字符长,称为单字符符号。而C语言中的其他一些符号,例如/*和==,包括了多个字符,称为多字符符号。当C编译器读入一个字符'/'后又跟了一个字符'*',那么编译器就必须做出判断:是将其作为两个分别的符号对待,还是合起来作为一个符号对待。C语言解决这个问题的方法可以归纳为一个很简单的规则:每一个符号应该包含尽可能多的字符。也就是说,编译器将程序分解成符号的方法是:从左到右一个字符一个字符地读入,如果该字符可能组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符串是否可能是一个符号的组成部分;如果可能,继续读入下一个字符,重复上述判断,直到读入的字符组成的字符串已不再可能组成一个有意义的符号。例如:a---b与表达式a -- - b的含义相同,而与a - -- b 的含义不同。 y = x/*p中的."/*"表示注释的开始,而不是除以*p。

2.理解函数声明

例子:解释 (*(void(*)())0)(); 这个语句的含义。
虽然上面的这个语句比较复杂,但是其实构造这类表达式其实只有一条简单的规则:按照使用的方式来声明。任何C变量的声明都由两部分组成:类型以及一组类似表达式的声明符。例如,声明一个int型变量a,int a;一旦我们知道了如何声明一个给定类型的变量,那么该类型的类型转换符就很容易得到:只需要把声明中的变量名和声明末尾的分号去掉,再将剩余的部分用一个括号整个“封装”起来即可。例如:float (*h)();表示h是一个指向返回值为浮点类型的指针,因此(float (*)())表示一个“指向返回值为浮点类型的函数的指针的”类型转换符。此时,(*(void(*)())0)(); 也就不难理解了,(void(*)())0表示将0强制转化为(void(*)())类型,然后是'*'的解引用,然后是函数调用。可以使用typedef使得上面的例子更简洁,typedef void (*funcptr)(); 那么 (*(void(*)())0)();可表示为(*(funcptr)0)();

3.变量的定义与声明要保证类型一致

如果在一个源文件中定义了char filename[] = "/etc/passwd";而在另外一个文件中声明了extern char* filename;尽管在一个语句中引用filename的值将得到指向该数组起始元素的指针,但是filename的类型是“字符数组”,而不是“字符指针”。在第二个声明中,filename被确定为一个指针。这两个队filename声明使用储存空间的方式是不同的,它们无法以一种合乎情理的方式共存。字符数组filename的内存布局如图1所示,字符指针filename的内存布局如图2所示。

图1 字符数组filename的内存布局示意图

图2 字符指针filename的内存布局示意图

4.返回整数的getchar函数

考虑下面的函数:


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值