C陷阱与缺陷(二)
第二章 语法陷阱
2.1 理解函数声明
(*(void(*)())0)();
任何C变量的声明都由两部分组成:类型以及一组类似表达式的声明符。
一旦我们知道了如何声明一个给定类型的变量,那么该类型的类型转换符只需要添加一个括号即可的到。
例如 float (*h)();表示h是一个指向返回值为浮点类型的函数的指针。
因此(float (*h)())表示一个"指向返回值为浮点类型的函数的指针"的类型转换符。
第一步假设fp是一个函数指针,那么通过(*fp)()调用fp所指向的函数,可以简写问fp()。
在表达式(*fp)()中,*fp两侧的括号非常重要,因为函数运算符()的优先级高于单目运算符*。
如果没有括号则*fp()效果等同于*((*fp)())的简写形式。
我们本意是(*0)();但是上式并不能生效,因为运算符*必须要一个指针来做操作数。而且这个指针还应该是一个函数指针。
因此在上式中必须对0作类型转换。
如果fp是一个指向返回值为void类型的函数的指针,那么(*fp)()的值为void,fp的声明如下:void (*fp)();
将常数0转型为“指向返回值为void的函数的指针”类型,可以这样写:(void (*)())0
2.2 运算符的优先级问题
优先级最高者其实并不是真正意义上的运算符,包括:数组下标、函数调用操作符各结构成员选择操作符。它们都是从左到右结合。
单目运算符的优先级仅次于前述运算符。单目运算符是从右到左。
接下来就是双目运算符。其中,算术运算符的优先级最高,移位运算符次之,关系运算符再次之,接着就是逻辑运算符、赋值运算符。
再下来就是三目运算符即条件运算符。
任何两个逻辑运算符都具有不同的优先级,每个与比每个或优先级高。
所有赋值运算符的优先级都是一样的从右到左。
在所有的运算符中,逗号运算符的优先级最低。
2.3 注意作为语句结束标志的分号
在if或者while语句之后需要紧跟一条语句时,如果此时多了一个分号,那么原来紧跟在if或者while子句之后的语句就是一条单独的语句,与条件判断部分没有了任何关系。
还有一种情形,当一个声明的结尾紧跟一个函数定义时,如果声明结尾的分号被省略,编译器可能会把声明的类型视作函数的返回值类型。
例如
struct log{
int date;
int time;
int code;
}
main()
{
...
}
上面代码实际的效果是声明函数main的返回值是结构log类型。
2.4 switch语句
C语言的switch语句的控制流程能够依次通过并执行各个case部分,要注意使用break语句及时把case中断。
我们可以在不添加break的部分添加一行注释 /*此处没有break语句*/
2.5 函数调用
f();是一个函数调用语句
f;这个语句计算函数f的地址,却并不调用该函数。
2.6 悬挂else引发的问题
else的原则是就近原则。
C语言允许初始化列表中出现多余的符号,例如
int das[]={31,28,31,};
C陷阱与缺陷(二)的更多相关文章
- C陷阱和缺陷学习笔记
这段时间把<C陷阱和缺陷>看了,没时间自己写总结.就转一下别人的学习笔记吧http://bbs.chinaunix.net/thread-749888-1-1.html Chapter 1 ...
- 阅读《C陷阱与缺陷》的知识增量
版权声明:本文为Focustc原创文章.转载请注明作者及出处. https://blog.csdn.net/caozhankui/article/details/35925939 看完<C陷阱与 ...
- 读书笔记--C陷阱与缺陷(一)
要参与C语言项目,于是作者只好重拾C语言(之前都是C++,还是C++方便). 看到大家都推荐看看 C陷阱与缺陷(C traps and pitfalls),于是好奇的开始了这本书的读书之旅. 决定将 ...
- 读书笔记--C陷阱与缺陷(七)
第七章 1.null指针并不指向任何对象,所以只用于赋值和比较运算,其他使用目的都是非法的. 误用null指针的后果是未定义的,根据编译器各异. 有的编译器对内存位置0只读,有的可读写. 书中给出了一 ...
- [C陷阱和缺陷] 第1章 词法“陷阱”
有感自己的C语言在有些地方存在误区,所以重新仔细把"C陷阱和缺陷"翻出来看看,并写下这篇博客,用于读书总结以及日后方便自身复习. 第1章 词法"陷阱" 1.1 ...
- C语言学习书籍推荐《C陷阱与缺陷》下载
下载地址:点我 凯尼格 (作者), 高巍 (译者) <C和C++经典著作:C陷阱与缺陷>适合有一定经验的C程序员阅读学习,即便你是C编程高手,<C和C++经典著作:C陷阱与缺陷> ...
- 《C陷阱与缺陷》整理二
1.数组名作实參 在C语言中,我们没有办法将一个数组作为函数參数传递,假设我们使用数组名作为參数.这个时候数组名立马会被转换为指向该数组的第一个元素的指针. 关于这一点的理解能够向前深 ...
- 读书笔记--C陷阱与缺陷(二)
第二章 1. 理解函数声明 书中分析了复杂的类型声明方式,也说明了使用typedef声明会更好理解,推荐大家使用typedef进行函数声明. 书中类型分析一层一层挖掘,让读者可以理解多层嵌套的类型含义 ...
- 程序员必知的Python陷阱与缺陷列表
本文关注的主要是python陷阱,具体而言,是指CPython,而且除非特别说明,所有代码示例都是在python2.7运行的. 我个人对陷阱的定义是这样的:代码看起来可以工作,但不是以你“想当然“”的 ...
随机推荐
- Swift中类的初始化器与继承
初始化是类,结构体和枚举类型实例化的准备阶段.这个阶段设置这个实例存储的属性的初始化数值和做一些使用实例之前的准备以及必须要做的其他一些设置工作. 通过定义构造器(initializers)实现这个实 ...
- The Linux device model
/sys和 /dev的疑问 1./dev 下放的是设备文件,是由应用层mknod创建的文件.假设底层驱动对mknod的设备号有相应的驱动,如open等函数.那么应用层open "/dev/* ...
- 如何写出专业级OOP程序-----文档注释
由于时间的限制就写一些通用的注释啦> @author 姓名 这个标记将产生一个作者条目,可以使用多个@author注释,每个对应一个作者. @version 文本 这个标记产生版本条目,对当前版 ...
- HTTP请求和数据安全
/*------------------------------------- 01 HTTP请求 ---------------------------------------*/ 重点:1.超文本 ...
- Android核心基础
第三代移动通讯技术(3rd Generation) ,支持高速数据传输的蜂窝移动通讯技术.3G与2G的主要区别是传输数据的速度. 1987年,第一台模拟制式手机(1G)问世,只能进行语音通话,型号:摩 ...
- Objective-C继承
继承只是想谈谈在OC中继承的理解:面向对象语言中一个主要的功能就是继承.继承可以使用现在类的所用功能,是对功能的扩展,通过继承创建的新类称为“子类”或“派生类”,被继承的称为“基类”或者“父类”.继承 ...
- POJ 1840 Brainman(逆序对数)
题目链接:http://poj.org/problem?id=1804 题意:给定一个序列a[],每次只允许交换相邻两个数,最少要交换多少次才能把它变成非递降序列. 思路:题目就是要求逆序对数,我们知 ...
- [IOI1996] USACO Section 5.3 Network of Schools(强连通分量)
nocow上的题解很好. http://www.nocow.cn/index.php/USACO/schlnet 如何求强连通分量呢?对于此题,可以直接先用floyd,然后再判断. --------- ...
- [NOIP1999提高] CODEVS 1047 邮票面值设计(dfs+dp)
dfs出邮票的各种面值,然后dp求解. ------------------------------------------------------------------------------- ...
- Lucence.net索引技术 一
1.建立索引 为了对文档进行索引,Lucene 提供了五个基础的类,他们分别是 Document, Field, IndexWriter, Analyzer, Directory.下面我们分别介绍一下 ...