当前位置: 首页 > news >正文

C陷阱和缺陷--第二章 “语法陷阱”

2.1 理解函数声明

因为 fp 是一个函数指针,那么*fp就是该指针所指向的函数,所以 (*fp)() 就是调用该函数的方式;ANSI C标准允许程序员将上式简写成 fp() ;

// 函数声明
void (*fp)();// 函数调用
(*fp)();

typedef void(*fp)(void *) 函数释义

// fp是一个指向返回值为void,参数为void *类型的指针
void(*fp)(void *)// fp不再是一个函数指针了,它代表着一种类型,这种类型可以定义一个指向返回值为void,参数为void *类型的指针
typedef void(*fp)(void *)// 使用示例
typedef void(*fp)(void *);		// 函数指针定义
fp func_fp;									// 函数指针声明
void func(void *);
func_fp=func;								// 函数指针赋值
func_fp();									// func_fp() 等于 func()

2.2 运算符的优先级问题

计算C语言运算符优先级的时候,不仅要考虑 优先级的先后顺序,还要考虑 结合性(自左向右,自右向左);

由上至下,优先级依次递减

在这里插入图片描述

!= 运算符的优先级要高于 &
if (flag & number != 0) 和 if (flag & (number != 0))

// 判断表达式的值是否为0
if (flag & number)// 优化一下写法
if (flag & number != 0)
// 实际则会引起歧义,因为 != 运算符的优先级要高于 & ;所以 (number != 0) 只能返回 1或者0
if (flag & (number != 0))

加法运算的优先级要比移位运算的优先级高
不要在移位运算中使用 + 号

r = hi<<4 + low;
// 等价于
r = hi<< (4+low);// 正确写法
r = (hi<<4) + low;
r = hi<<4 | low;

因为函数调用的优先级要高于单目运算符
所以如果 p 是一个函数指针,要调用 p 所指向的函数

// 正确写法
(*p)()p()// 错误写法
*p()  等价于  *(p())

单目运算符是自右至左结合
*p++ 会被编译器解释为 *(p++), 而不是 (*p)++

赋值运算符的优先级是从右到左
a=b=0; 等价于 b=0;a=b;

赋值运算符的优先级要低于任何一个比较运算符
if (c=getc(in) != EOF) 等价于 if (c = (getc(in) != EOF))

2.3 注意作为语句结束标识的分号

现在的编译器应该都可以识别出来不带分号的报错,但是还是需要多加注意;
不要在 if 或 while 等判断语句后面增加分号;

if (a > big);a = big;
// 等价于
if (a > big){};a = big;

不要遗漏了分号

if (a > big)return			// 希望程序结束
a = 3;
// 等价于
if (a > big)return a = 3;
// 本来想定义一个结构体和一个函数,下面的代码会被解释为 func1函数的返回值类型为 bigger
struct bigger
{int test_a;int test_b;
} 
func1()
{
// ...
}

2.4 switch 语句

switch 语句可以缺少 break 语法,有优势也有劣势

// 正确写法
switch(number)
{case 1:printf("red");break;case 2:printf("yellow");break;
}
// 错误写法 当number=1的时候,会打印出 redyellow
switch(number)
{case 1:printf("red");case 2:printf("yellow");break;
}// 优势用法,当number==1或2 的时候,都可以打印出 yellow
switch(number)
{case 1:case 2:printf("yellow");break;
}

2.5 函数调用

在函数调用时候,即使函数不带参数,也应该包括参数列表

func();	// 正常函数调用
func   // 表示计算函数的地址

2.6 悬挂else引发的问题

else始终和同一括号内最近的未匹配的if结合,千万不要省略{}

// 期望 x 不等于0的时候进行计算
if (x == 0)if (y == 0) error();
else
{z = x +y;
}
// 等价于
if (x == 0)
{if (y == 0) error();else{z = x +y;}
}// 正确写法
if (x == 0)
{if (y == 0) error();
}
else
{z = x +y;
}

像shell语法中定义, 使用收尾定界符可以避免else悬挂问题

if x==0
thenelsefi

相关文章:

  • MyBatis---初阶
  • 【C语言】中的位操作符和移位操作符,原码反码补码以及进制之间的转换
  • Leetcode刷题笔记题解(C++):203. 移除链表元素
  • Spring Boot项目中TaskDecorator的应用实践
  • 第六十四天 服务攻防-框架安全CVE复现Apache shiroApache Solr
  • 如何使用Coded UI Test对Webpage进行自动化测试
  • FlashMeeting(基于FFmpeg+openCV)视频语音通讯系统
  • Java 爬虫 jvppeteer
  • 美易平台:全球金融市场一周前瞻G20会议至美联储纪要,关键事件点评
  • 【研究生复试】计算机软件工程人工智能研究生复试——资料整理(速记版)——自我介绍(英文)
  • .net 微服务 服务保护 自动重试 Polly
  • Java 面向对象进阶 10 多态中调用成员的特点(黑马)
  • 代码随想录刷题第38天
  • Docker中如何删除某个镜像
  • 【微服务生态】Docker
  • .pyc 想到的一些问题
  • docker容器内的网络抓包
  • egg(89)--egg之redis的发布和订阅
  • JS+CSS实现数字滚动
  • Koa2 之文件上传下载
  • windows下如何用phpstorm同步测试服务器
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 前端知识点整理(待续)
  • 我的面试准备过程--容器(更新中)
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • ​如何防止网络攻击?
  • #NOIP 2014# day.1 T3 飞扬的小鸟 bird
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • (2009.11版)《网络管理员考试 考前冲刺预测卷及考点解析》复习重点
  • (C++)八皇后问题
  • (LeetCode 49)Anagrams
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (Note)C++中的继承方式
  • (附源码)计算机毕业设计SSM在线影视购票系统
  • (蓝桥杯每日一题)平方末尾及补充(常用的字符串函数功能)
  • (一)Java算法:二分查找
  • (译)计算距离、方位和更多经纬度之间的点
  • ****** 二十三 ******、软设笔记【数据库】-数据操作-常用关系操作、关系运算
  • **python多态
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
  • .java 指数平滑_转载:二次指数平滑法求预测值的Java代码
  • .net core 6 集成 elasticsearch 并 使用分词器
  • .NET Micro Framework初体验
  • .Net Remoting(分离服务程序实现) - Part.3
  • .NET 表达式计算:Expression Evaluator
  • .NET 读取 JSON格式的数据
  • .net 反编译_.net反编译的相关问题
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法
  • .net反编译的九款神器
  • .NET简谈设计模式之(单件模式)
  • @FeignClient 调用另一个服务的test环境,实际上却调用了另一个环境testone的接口,这其中牵扯到k8s容器外容器内的问题,注册到eureka上的是容器外的旧版本...
  • @media screen 针对不同移动设备
  • [ 手记 ] 关于tomcat开机启动设置问题