预处理算法
#和##是两个预处理运算符(注意不是C语言表达式的运算符),#后接形参(中间能够空格),用于建立字符串字面值;##用于链接两个形参。shell
函数式宏定义也能够带可变参数,一样是用…表示可变参数,宏定义中的可变参数的部分用_VA_ARGS_表示。如:编程
#define showlist(…) printf(#_VA_ARGS_)windows
取消宏定义用#undef ,取消未定义的宏不算错误。函数
对条件预处理的编译(#if … #elseif… #else… #endif),可选的方法有:一、手动编辑代码,添加定义目标宏;二、在全部须要配置的源文件开头包含一个头文件,在该头文件中定义目标宏;三、经过gcc -D选项在编译时定义目标宏 43。spa
C标准中规定了几个特殊的宏,不需定义便可使用,最经常使用的是_FILE_ (展开成当前源文件名)和_LINE_(当前代码行的行号)。命令行
C99标准引入特殊标识符_func_可表示当前函数名,这是一个变量名(字符串变量)而不是宏定义。指针
第21章 Makefile基础code
make程序自动读取当前目录下的Makefile文件(依次查找名为GNUmakefile、makefile和Makefile,通常建议用Makefile作文件名)。blog
make执行的命令前加了@,则不显示命令自己而只显示输出结果,前加- ,则即便该命令出错也继续执行后面的命令。
Makefile中约定俗成的目标名字有:all(执行编译,一般为缺省)、install(执行编译后的安装工做,把可执行文件、配置文件、文档等分别复制到不一样的安装目录)、clean(删除编译生成的二进制文件)、distclean(不只删除二进制文件,也删除其余的生成文件)。
make中, := 赋值时遇到变量当即展开; ?= 赋值时若是没定义过,就进行定义并赋值(不当即展开),若是定义过了就什么也不作;还可以使用+=。
gcc 的 -M选项自动分析目标文件和源文件的依赖关系。
第22章 指针
gcc把字符串字面值分配在.rodata段,因此字符串字面值作右值时最好理解成const char* 类型。
在gdb中,能够在run或start命令后面加入命令行参数(从arg[1]开始),也能够用set args命令设置命令行参数以后用run或start运行程序。
两层指针若是是传出的,可能有两种状况:一、传出的指针指向静态内存,或指向已分配的动态内容;二、在函数中动态分配内存,而后传出的指针指向这块内存。
第23章 函数接口
回调函数
若是参数是函数指针,调用者能够传递一个函数的地址给回调函数的实现者,也就是说,调用者提供一个函数但本身不去调用它,而是让经过使用回调函数,让回调函数的实现者去调用它。
回调函数能够实现相似于C++的虚函数或者泛型算法的功能。
处理可变参数要用到C标准库的va_list类型和va_start、va_arg、va_end宏,它们都定义在stdarg.h头文件中。从下面的例子可大体看出具体的用法:
#include <stdio.h>
#include <stdarg.h>
void printlist(int begin,…)
{
va_list ap;
char *p;
va_start(ap,begin);
p=va_arg(ap,char *);
while(p!=NULL) {
fputs(p,stdout);
putchar('\n');
p=va_arg(ap, char*);
}
va_end(ap);
}
int main(void)
{
printlist(0,"hello","world","foo","bar",NULL);
return 0;
}
第24章 C标准库
Linux平台提供的C标准库包括:一、一组头文件,定义了不少类型和宏,声明了不少库函数和全局变量;二、一组库文件,提供了库函数和局变量的定义。
分割字符串:
char *strtok(char *str, const char *delim);
char *strtok_r(char *str, const char *delim, char **saveptr);
strtok会不断修改str的值,同时在函数中使用一个静态变量记住处理到字符串的位置,这使得strtok不可重入。而strtok_r不使用静态变量,而是要求调用者使用一个变量记录处理位置,并将处理位置传给strtok_r做为第三个参数。strtok_r中的r表示Reentrant(可重入的)。Man Page中有一个使用strtok_r的很好的例子,可对分割后的子串再进行分割处理。
windows的换行符是\r\n,Unix的换行符是\n。
fopen原型:FILE *fopen(const char *path,const char *mode); 打开文件出错,fopen返回NULL并设置errno。
FILE是C标准库中定义的结构体类型,包含了文件描述符、用户空间I/O缓冲区和当前读写位置等信息。像FILE *这样的指针称为不透明指针(Opaque Pointer)或句柄(Handle)。
fclose原型:int fclose(FILE *fp); fclose调用出错返回EOF并设置errno。
使用ls命令查看设备文件时,在普通文件显示文件大小的地方显示的是设备号(如5,0),其中主设备号5标识内核中一个设备驱动程序,次设备号标识该设备驱动程序管理的一个设备。
终端设备在shell进程启动时自动打开,并用三个FILE *指针stdin、stdout和stderr指向设备,这三个指针是libc中定义的全局变量,在stdio.h中声明,printf向stdout写,而scanf从stdin读。
fgetc函数从指定文件中读一个字节,getchar从标准输入中读一个字节,调用getchar()至关于调用fgetc(stdin)。fgetc返回值为int型(读取unsigned char要转换为int),由于它出错会返回EOF(0xffffffff),若是返回值为unsigned char型则没法区分是EOF仍是字节0xff。相对应的有fputc和putchar。
操做读写位置的函数fseek、ftell、rewind。原型以下:
int fseek(FILE *stream, long offset, int whence); //其中whence参数含义以下:SEEK_SET从开头移动offset个字节; SEEK_CUR从当前; SEEK_END从末尾。
long ftell( FILE *stream); //返回当前读写位置
void rewind(FILE *stream); //移动到文件开头
gets不能指定缓冲区大小,在编程时不该当使用。
函数printf、scanf有多种形式,其中以v开头表示可变参数不是以…的形式传进来,而是以va_list类型传进来。
使用scanf函数时要注意c%是能够匹配空白字符的,匹配时不会跳过,要想跳过开头的空白字符,能够在格式化字符串的c%前面用一个空格去匹配。
I/O缓冲区、flush、exit。