来复习一下C语言吧

  • 最近真是啥都看看,不如先来复习一下C语言。《C陷阱与缺陷》是我大一上基本看完《C Primer Plus》之后买的,但是学C学得差不多了之后又跑去学汇编了,所以这本书就荒废了。
  • 今天当当网又打折,买了本安卓的书,没看过的书有点多了。打算先把 Java放一放,来复习一下C语言吧
  • 这篇博客的代码都是看了《C陷阱与缺陷》后有感而发自己写的,内容可能断断续续,代码也可能有些不严谨。
  • 这坑挖了肯定是填不上了,这两天我能看多少写多少吧。要是看《C陷阱与缺陷》又烂尾了那这贴也就烂尾了,等来年复习C语言的时候再说吧(也可能再也不复习了)

一、函数指针

1.1 给函数指针赋值

#include<stdio.h>
void print(char *s)
{
    printf("%s",s);
}
int main()
{
    void (*fp) (char *);
    void (*fp2) (char *) = print;
    fp = &print;
    (*fp)("fp can print\n");
    (*fp2)("fp2 can print\n");
}
output:
fp can print
fp2 can print

自定义的 print() 函数既可以引用地址也可以当作一个对象,但注意的是应该用print 而不是用print() ,不然就是调用函数了。

所以在将其赋值给一个函数指针的时候既可以用fp = &print,也可以用 fp2 = print 。

1.2 带函数的函数参数

前阵子做bin经常会遇到将函数作为参数带入其它函数的例子,不知道是因为反编译的原因还是本来就是这么写的。这里我也试了下

#include<stdio.h>
void print(char *s)
{
    printf("%s",s);
}
void print2(void(*p) (char *))
{
    printf("We can print a string!\n");
    p("Nice Day!\n");
}
int main()
{
    void (*fp)(void(*) (char *)) = print2;
    (*fp)(print);
}
output:
We can print a string!
Nice Day!

1.3 返回一个函数的函数

#include<stdio.h>
void print(char *s)
{
    printf("%s",s);
}
void (*print2()) (char *)
{
    printf("It looks so difficult.\n");
    return print;
}
int main()
{
    void (* ((*fp) ())) (char *) = print2;
    (*fp)()("But it is pretty ez, right?");
}
output:
It looks so difficult.
But it is ez, right?

搞这个试错了好几次。。。逻辑上有点搞

void (*print2()) (char *) 的意思是print2()函数返回一个void (*) (char *)的函数。所以最后可以直接在fp()后跟上参数

为什么要故意搞成这样呢,主要是因为反编译的C语言经常就是长这个b样的,就算没这么复杂,写写这个也有助于逆向的时候对程序的分析。

1.4 函数调用

C语言要求,在函数调用时即使函数不带参数,也应该包括参数列表。因此,如果 f 是一个函数,

f();

是一个函数调用语句,而

f;

却是一个什么都不做的语句。更精确的说,这个语句计算函数 f 的地址,却并不调用该函数。

所以事实上,1.1中的

fp = &print;

其实也可以写成

fp = print;

1.9 附加

另外,我在第一遍写这些代码的时候写错了,我把函数指针的调用写成了 fp(); / fp2(); 这样的形式。

这样也是可以实现的。那么,是为什么呢?我想,大概是因为

fp是指针,那print() 中的 print 是什么?应该是print() 的首地址

那么将指针指向print() ,实际上fp中存储的是函数的首地址。

所以在调用的时候,(*fp)会解引用到print(),而fp也会直接调用fp中值所指向的地址处的函数

这跟栈中存储返回地址不是一个道理么。C语言果然是很灵活啊

二、运算符优先级

2.1 最重要的两点

  1. 任何一个逻辑运算符的优先级低于任何一个关系运算符
  2. 移位运算符的优先级比算术运算符要低,但是比关系运算符要高

书中的示例:

if (flag & FLAG != 0)... 实际上被解释为: if (flag & (FLAG != 0) )...

r = hi<<4 + low; 实际上相当于: r = hi<< (4 + low);

2.2 其它

  • 运算符==和!=的优先级要低于其他关系运算符的优先级
  • 每个“与”运算符要比相应的“或”运算符优先级高
  • 三目条件运算符优先级最低
  • 所有的赋值运算符的优先级是一样的,而且它们的结合方式是从右到左
  • 在所有的运算符中,逗号运算符的优先级最低。逗号运算符常用于在需要一个表达式而不是一条语句的情形下替换作为语句结束标志的分号。逗号运算符在宏定义中特别有用

说点什么

avatar

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

  Subscribe  
提醒