__VA_ARGS_是一个可变参数的宏,是新的c99规范中新增的,目前似乎只有gcc支持(VC6.0不支持)
宏定义中参数列表的最后一个参数为省略号(也就是3个点),这样预定义宏__VA_ARGS_就可以用在替换部分中,替换省略号所代表的字符串。
比如define PR(...) printf(__VA_ARGS_)
int main()
{
int wt=1,sp=2;
printf("hello\n");
printf("weight=%d, shipping=%d\n", wt, sp);
return 0;
}
输出结果:
hello
weight=1, shipping=2
注意省略号只能代替最后面的宏参数,#define W(x, ..., y)错误!
详细介绍的链接:http://blog.csdn.net/luckywang1103/article/details/42835619
在类函数宏的替换部分,#用作一个预处理运算符,将语言符号转化成字符串,该过程为字符串化。
#include <stdio.h>
#define PSQR(x) printf("the square of" #x "is %d.\n", (x)*(x))
int main()
{
int y=4;
PSQR(y);
PSQR(2+4);
return 0;
}
输出结果为:
the square of y is 16.
the square of 2+4 is 36.
##可用作于类函数宏的替换部分,也可用作类对象宏的替换部分。这个运算符把两个语言符号组合成一个语言符号。
#include <stdio.h>
#define XNAME(n) x##n
#define PXN(n) printf("x"#n" =%d.\n", x##n)
int main()
{
int XNAME(1) = 12; //int x1 = 12;
PXN(1); //printf("x1 =%d.\n", x1);
return 0;
}
输出结果为:
x1 =12.
FD_ZERO(fd_set *fdset);将指定的文件描述符集清空,在对文件描述符集合进行设置前,必须对其进行初始化,如果不清空,由于在系统分配内存空间后,通常并不作清空处理,所以结果是不可知的。
FD_SET(fd_set *fdset);用于在文件描述符集合中增加一个新的文件描述符。
FD_CLR(fd_set *fdset);用于在文件描述符集合中删除一个文件描述符。
FD_ISSET(int fd,fd_set *fdset);用于测试指定的文件描述符是否在该集合中。
offsetof用来判断结构体中成员的偏移位置,需要头文件stddef.h
#define offsetof(type, member) (size_t)&(((type *)0)->member)
巧妙之处在于将地址0强制转换为type类型的指针,从而定位到member在结构体中的偏移位置,编译器认为0是一个有效的地址,从而认为0是type指针的起始地址。
typeof是GNU对C新增的一个扩展关键字,用于获取一个对象的类型,很多时候我们处理的对象是一个指针类型,如果想知道指针所指向的对象的类型,就派上用场了。
container用来根据成员的地址来获得结构体的地址,需要头文件linux/kernel.h
#define container_of(ptr, type, member)
({ const typeof( ((type *)0)->member ) *__mptr = (ptr);
(type *)( (char *)__mptr - offsetof(type, member) );
})
container_of宏分两部分,
第一部分:const typeof( ((type *)0)->member) *__mptr = (ptr);
通过定义一个member指针类型的指针变量__mptr,并将ptr赋值给__mptr
第二部分:(type *)( (char *)__mptr - offsetof(type, member) )
通过offset宏计算出member在type中的偏移,然后用member的实际地址__mptr减去偏移,得到type的起始地址,即指向type类型
http://blog.csdn.net/luckywang1103/article/details/8802459
C++和C中命名变量时不能以数字开头,定义宏时也不能,否则编译结果显示预处理时出错,显示信息为error: macro names must be identifiers。
像10_MODE这样的定义是错误的,应该改成MODE_10
区别在于后者可以组成复杂的预编译条件,比如:
#if defined(AAA) & defined(BBB)
xxxxx
#elif defined(CCC)
xxxxx
#endif
而#ifdef就不能用上面的用法,只能判断单个宏是否定义。
在if else语句中根据预判使用likely与unlikely宏
#define likely __builtin_expect((x), 1)
#define unlikely __builtin_expect((x), 0)
#include <stddef.h>
offsetof(structName, memberName);
举例:
struct af_alg_iv {
__u32 ivlen;
__u8 iv[0];
};
offsetof(struct af_alg_iv, iv); 计算得到iv的偏移量为4
http://blog.csdn.net/luckywang1103/article/details/18139677
typedef自定义函数指针类型
#include <stdio.h> typedef int (*fp_t)(char c); int f0(char c) { printf("f0, c = %c\n", c); return 0;} int f1(char c) { printf("f1, c = %c\n", c); return 1;} int main() { int ret; fp_t fp; fp = f0; ret = fp('a'); fp = f1; ret = fp('x'); return 0; }
运行结果:
f0, c=a
f1, c=x
typedef自定义函数类型
#include <stdio.h> typedef int fp_t(char c); int f0(char c) { printf("f0, c = %c\n", c); return 0;} int f1(char c) { printf("f1, c = %c\n", c); return 1;} int main() { int ret; fp_t* fp; fp = f0; ret = fp('a'); fp = f1; ret = fp('x'); return 0; }
运行结果:
f0, c=a
f1, c=x
另外说明一下:函数名是一个指针,fun *t = funA
定义一个函数指针类型 函数名
需要申明为volatile的变量
硬件地址
多线程中共享的全局变量
中断服务程序和进程(线程)共享的全局变量
在一个32位系统上
type | bits | values |
|
8 | -127 to 127 |
unsigned char | 8 | 0 to 255 |
short | 16 | -32767 to 32767 |
unsigned short | 16 | 0 to 65535 |
int | 32 | -2,147,483,647 to 2,147,483,647 |
unsigned int | 32 | 0 to 4,294,967,295 |
long | 32 | -2,147,483,647 to 2,147,483,647 |
unsigned long | 32 | 0 to 4,294,967,295 |
long long | 64 | -9,223,372,036,854,775,807 to 9,223,372,036,854,775,807 |
unsigned long long | 64 | 0 to 18,446,744,073,709,551,615 |
__int128为128 bit长度的类型
gcc中long int一般是32 bit,long long int一般是64 bit,但是随着PC硬件的不同和gcc的不同实现可能会有不同
int access(const char *filename, int amode);
amode参数为0时表示检查文件的存在性,如果文件存在,返回0,不存在,返回-1。
该函数还可以检查文件的其他属性。
06检查读写权限
04检查读权限
02检查写权限
01检查执行权限
00检查文件存在性
int atexit(void (*func)(void));
#include<stdlib.h>
注册终止函数,即main函数结束后调用的函数。
一个进程可登记多达32个函数,这些函数将由exit自动调用。
atexit注册的函数类型应为不带任何参数的void函数,exit调用这些注册函数的顺序与注册他们的顺序相反。同一个函数如若登记多次,也会被调用多次。
实例:
#include <stdio.h>
#include <stdlib.h>
void exit_fn1(void)
{
printf("Exit function #1 called\n");
}
void exit_fn2(void)
{
printf("Exit function #2 called")
}
int main()
{
atexit(exit_fn1);
atexit(exit_fn2);
return 0;
}
输出结果:
Exit function #2 called
Exit function #1 called
char *strdup(char *str)
malloc是分配虚拟地址空间,如果不memset或者bzero,那么就不会分配实际的物理页面。
内存池的作用看名字也能猜到,"池"意味着资源是统一管理和创建释放的,就像数据库的连接池、系统的线程池。主要就是为了避免创建、销毁资源的代价。c标准的malloc/free会造成大量的内存碎片以至于影响效率,所以“内存池”的技术某种程度上避免了这种消耗和影响。