C陷阱与缺陷(学习笔记)
前言
掌握细节并不难,难的是如何运用之妙!
词法“陷阱”
词:单词
符号=作为赋值运算,是因为操作频繁,书写简单
词法分析中的“贪心法”
- a---b与表达式a -- - b的含义相同,而与a - -- b的含义不同
- y = x/*p与y = x / *p不同(第一个/*被理解为注释符)
理解:这也许就是编码规范要求操作符两侧添加合理空格的原因之一吧
字符与字符串
- 用双引号引起的字符串,代表的却是一个指向无名数组起始字符的指针。
- 字符’\0’对应的十进制是0
语法“陷阱”
运算符优先级
括号(),数组下标[],函数调用,结构成员选择操作符->/. > 单目运算符 > 算数运算符 > 移位运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符 > 条件运算符(三目运算符)
- *p++,先计算p++
- while (c=getc(in) != EOF)和while ((c=getc(in)) != EOF)
switch语句
- case语句结束时不加break的场景,最好加上注释// fall-through
练习题:
- 为什么C语言允许初始化列表中出现多余的逗号,如:
int a[] = {1, 2,
};enum {a,b,
};
据说是为了简化代码生成工具的逻辑处理。
语义“陷阱”
指针与数组
C语言中的数组值得注意的地方有以下两点:
- C语言中只有一维数组,而且数组的大小必须在编译期就作为一个常数确定下来。然而,C语言中数组的元素可以是任何类型的对象,当然也可以是另外一个数组。这样,要“仿真”出一个多维数组就不是一件难事。
(备注:C99标准允许变长数组(VLA)) - 对于一个数组,我们只能够做两件事:确定该数组的大小,以及获得指向该数组下标为0的元素的指针。其他有关数组的操作,哪怕它们乍看上去是以数组下标进行运算的,实际上都是通过指针进行的。换句话说,任何一个数组下标运算都等同于一个对应的指针运算,因此我们完全可以依据指针行为定义数组下标的行为。
边界计算与不对称边界
“栏杆错误”,也常被称为”差一错误“(off-by-one error)
问题:100英尺长的围栏每隔10英尺需要一根支撑用的栏杆,一共需要多少根栏杆?
解决方法:用第一个入界点和第一个出界点来表示一个数值范围,即[a, b)
如:x>=16且x<=37,表示成:x>=16且x<38
这个问题,还会出现在:队列,栈等缓冲区操作中
ANSI C标准明确允许这种用法:数组中实际不存在的”溢界“元素的地址位于数组所占内存之后,这个地址可以用于进行赋值和比较。
如:
#define N 1024
static char buffer[N];
static char *bufptr;bufptr = buffer;
……
if (bufptr == &buffer[N])
求值顺序
C语言中只有四个运算符(&&、||、?: 和,)存在规定的求值顺序。
- 运算符&&和||首先对左侧操作数求值,只在需要时才对右侧操作数求值
- 运算符?:有三个操作数:在a?b:c中,操作数a首先被求值,根据a的值再求操作数b或c的值
- 逗号运算符,首先对左侧操作数求值,然后该值被”丢弃“,再对右侧操作数求值。
整数溢出
”溢出“,是指有符号整数算术运算中发生的现象
预处理器
不能忽视宏定义中的空格
#define f (x) ((x)-1)
#define f(x) ((x)-1)
宏并不是函数
- #define max(a,b) ((a)>(b) ? (a) : (b)),每个参数用括号括起来,整个结果表达式也用括号括起来
- max(a++, b),参数不能出现副作用,a会被计算两次
- 避免宏展开成庞大的表达式,如:max(a,max(b,max(c,d)))
宏并不是语句
assert宏
#define assert(e) if (!e) assert_error(__FILE__, __LINE__)
例子:
if (x > 0 && y > 0)assert(x > y);
elseassert(y > x);
展开后:
if (x > 0 && y > 0)if (!(x > y)) assert_error("foo.c", 37);
elseif (!(y > x)) assert_error("foo.c", 39);
问题:出现了if和else重新组队。
#define assert(e) { if (!e) assert_error(__FILE__, __LINE__); }
展开后:
if (x > 0 && y > 0){ if (!(x > y)) assert_error("foo.c", 37) };
else{ if (!(y > x)) assert_error("foo.c", 39) };
问题:else之前的分号是一个语法错误
#define assert(e) ((void)((e) || assert_error(__FILE__, __LINE__)))
展开后:
if (x > 0 && y > 0)((void)((x > y)) || assert_error("foo.c", 37)));
else((void)((y > x)) || assert_error("foo.c", 39)));
理解:
- if, else代码块加{},所以代码规范一般要求,即便只有一条语句的代码块也要加{}
- 根据宏具体作用定义形式,有的需要定义成表达式,有的需要定义成语句块(用do{ } while(0)包裹宏内容)
宏并不是类型
#define T1 struct foo *
typedef struct foo * T2;T1 a, b; // 扩展为:struct foo * a, b; 一个是指针变量,一个是结构体变量
T2 a, b;
C陷阱与缺陷(学习笔记)相关推荐
- C陷阱与缺陷学习笔记
导读 程序是由符号(token)序列所组成的,将程序分解成符号的过程,成为"词法分析". 符号构成更大的单元--语句和声明,语法细节最终决定了语义. 词法陷阱 符号(token)指 ...
- C陷阱与缺陷阅读笔记(上)
词法陷阱 1.贪心法 C编译器对C语言符号的识别,基于每一个符号应该包含尽可能多的字符原则. 如果输入流截止至某个字符之前都已经分解成为一个个符号,那么下一个符号将包括从该字符之后可能组成一个符号的最 ...
- C陷阱与缺陷阅读笔记(下)
关于printf函数 printf函数将数据写到标准输出,fprintf函数将数据写到任何文件,sprintf函数格式化字符串.这三个函数的返回值都是已经处理的字符数. sprintf函数作为输出数据 ...
- 《C语言陷阱和缺陷》笔记
原著:Andrew Koenig - AT&T Bell Laboratories Murray Hill, New Jersey 07094 翻译:lover_P 修订:CQBOY 来自:h ...
- C陷阱与缺陷学习总结
总结序言: 学习大牛们的书籍,每次都是新潮澎湃,热血沸腾,看他们的书心中就有一种信任,有一种无比的膜拜.最初看到这本书的时候心情也是如此.Andy这个大牛我想大家也都如雷贯耳了吧.从图书馆找到他的书籍 ...
- 《c陷阱与缺陷》笔记--注意边界值
如果要自己实现一个获取绝对值的函数,应该都没有问题,我这边也自己写了一个: void myabs(int i){if(i>=0){printf("%d\n",i);}else ...
- C陷阱与缺陷--读书笔记3 语义“陷阱”
第三章 一.知识点 1.C语言中的数组值得注意的地方有以下两点:(P41) (1).C语言中只有一维数组,而且数组的大小必须在编译期就作为一个常数确定下来.然而,C语言中数组的元素可以是任何类型的对象 ...
- 《C陷阱与缺陷》学习笔记
第一章 词法陷阱 笔记本:<C陷阱与缺陷> 创建时间:2018/4/23 22:06:21 ...
- 《C陷阱与缺陷》学习笔记(2):作者有话说
道阻且长,行则将至.埋头苦干,不鸣则已,一鸣惊人!加油,骚年! 1 参考资料 1.书本参考资料 <C陷阱与缺陷>前言: 2.网络参考资料 [维基百科]Andrew Koenig:https ...
- 【2018深信服 醒狮计划】《C陷阱与缺陷》学习笔记
2018深信服"醒狮计划"笔记 先自我介绍一下,湖大研一计算机的菜鸡,本科网络工程的,大学里不务正业一直在做应用,大一自学过一段时间的MFC,Windows网络编程,感觉比控制台好 ...
最新文章
- Crystal For Rubyists 简体中文
- python结构嵌套_python2.3嵌套if结构:
- 黑莓GPRS上网套餐包月 300MB流量 不限CMWAP/CMNET
- 将Python源码编译成pyc和pyo文件
- 用php编写比赛评奖系统_php编写的抽奖程序中奖概率算法
- activemq和jms_保证主题,JMS规范和ActiveMQ的消息传递
- leetcode76 最小覆盖子串
- java--面对对象之final关键字和static关键字
- sql server 循环_学习SQL:SQL Server循环简介
- kafka的延迟操作-pull操作详解
- 【Linux】磁盘分区
- git pull 提示 There is no tracking information for the current branch
- 4ARM-PEG-OH 四臂PEG羟基
- python中判断无向图是否有环_数据结构与算法:17 图
- 求树的最大宽度(层次遍历法)
- 用“掩码位图“,制作类似.png的“透明图片“①
- 手机开发|USB调试时未弹出授权对话框
- 神器集合!这12个免费工具可以让您的工作更高效
- ViewCompanion Premium(HPGL、HPGL2和HP-RTL文件浏览和打印软件)官方正式版V13.10 | 内置viewcompanion注册码
- c# 画刻度尺(支持缩放)
热门文章
- 绕过cdn探测真实ip方法大全
- 5W1H 图书管理系统
- 全国省市区表完整版(自己整理)
- 台达PLC实现伺服电机的正反转
- python 会议室预约系统解决方案_快思聪FUSION会议预约系统
- 2020年日历电子版(打印版)_2020全年共12个月的日历表打印版可图片年历-2020年日历A4打印版(每月一张-横版-完美版)下载Word带节假日农历电子版-西西软件下载...
- 如何录制Gif动态图片
- Android Studio ADB 环境变量配置
- 主机安全扫描入门-用Java封装Nmap
- vue实例的参数说明