语法“陷阱”

C陷阱与缺陷

0x00理解函数声明

(*(void(*)())0){};
  • 构造表达式的简单规则:任何 C 变量的声明都由两部分(类型 以及 一组类似表达式的声明符)
float *g(),(*h)()
// 表示 *g() 与 (*h)()是浮点表达式,因为()结合优先级高于* *g() <=> *(g()) 
//g 是一个函数,该函数的返回值类型为指向浮点数的指针
//h 是一个函数指针,h所指向函数的返回值为浮点类型
(float (*)())
//表示一个指向返回值为浮点数类型的函数指针
// fp是一个函数指针,如何调用 fp 所指向的函数
// 因为fp是一个函数指针,那么*fp就是该指针所指向的函数,所如下就是调用该函数的方法。
(*fp)() 

0x01运算符的优先级问题

在这里插入图片描述

0x02注意作为语句结束标志的分号

  • C 语言中多写了一个分号可能造成的后果:

    • 被视作一个不会产生任何实际效果的空语句
    • 编译器因为这个分号产生一条警告信息
  • 少写一个; 在 return 后面少写 ; 可能不会报错,只是会返回 return 后的值。如果之前的函数的返回值类型为 void 则会因为返回值不一致而报错。如果省略了返回值类型,则可能不会报错,因为编译器会隐含的将返回值类型视为 int 。

    //例
    if(n < 3)
    	return
    logrec.date = x[0]
    
  • 如果一个声明的结尾紧跟一个函数定义时,如果声明结尾的分号被省略,编译器可能会把声明的类型视作函数的返回值类型。

    // 例
    struct lonrec{
    int date;
    }
    main(){
    
    }
    

0x03switch 语句

  • C 语言根据其设计会因为 case 语句后面的 break 的有无而执行情况不同(如果没有 break 会一直执行到 break 或执行完),可以利用此特性的方便设计解决问题的程序。

    // example1.c
    // 加减法示例,只要将第二个操作数的正负号反号后,
    // 减法和假发运算处理本质上就是一样的,
    // 这样会大大方便程序的处理
    
    case SUBTRACT:
    	opend2 = - opend2;
    	/* 此处没有 break 语句*/
    case ADD:
    	......
    
    // example2.c
    // 字符统计示例,忽略空白字符(\n \t ' ')
    case '\n':
    	linecount ++;
    case '\t':
    case ' ':
    

0x04函数调用

  • 与其他程序设计语言不同,C 语言要求:在函数调用时使用函数不带参数,也应该包括参数列表。
    // 因此如果 f 是一个函数:
    f();
    // f(); 是一个函数调用语句,
    f;
    // f; 是一个什么也不做的语句。更精确地说,这个语句计算函数 f 的地址,却不调用该函数。
    

0x05"悬挂" else 引发的问题

// else1.c
if (x == 0)
	if (y == 0)
		error();
else{
	z = x + y;
	f(&z);
}
// else2.c
// 上边 else1.c 的代码会被编译器理解成如下缩进
if (x == 0)
	if (y == 0)
		error();
	else{
		z = x + y;
		f(&z);
	}
// 因为C语言中有这样的规则,
// else 始终与同一对括号内最近的未配置的 if 结合。
// else3.c
// 如果想要被编译器理解成 else1.c 缩进形式则需要写成下边形式
if (x == 0){
	if (y == 0)
		error();
}
else{
	z = x + y;
	f(&z);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值