c语言基础
2014-08-04 11:09
134 查看
有些容易忘的,记录一下。
typedef int *PINT
有一本书说的好,typedef类似于变量定义,只不过把变量名换成类型名。
上面例子可以这样记忆:定义一个指针类型PINT,其指向int。以前老是忘记的typedef用法,立即跟变量定义联系上,恐怕想忘都忘不了。
不过有特例:typedef int(pFunc)(char *, int);定义了一个函数类型pFunc,其指向一个返回值为int型、参数为char指针、int型的函数。
介绍下这本书:<<深入理解计算机系统>>,很适合初学者又有心进阶的人,正在缓慢学习中
typeof(x)
按照gcc man手册说法,这是gcc的特性,就像asm一样,不过有些标准不支持这些特性,如:在选项中加上-ansi或-std=c90后这些特性不生效(没试过)。
用法:
以上都表示int这个类型。
在内核的typecheck.h和module.h中都可以看到这种用法。
1UL 等于1ul
常量后面的后缀大小写通用
数组的特殊初始化方式
嵌套宏的前后顺序无特定要求
前面的调用后面的,不会报错(其实只是替换,在.c程序前面能找到这个宏可以替换就不会报错)
但假如不是嵌套宏,那前后顺序有要求
break只能跳出一层
每个break只能跳出当前循环
strtol(const char *nptr, char **endptr, int base)
当输入字符串nptr含有16进制数,需要致命base为16
不同函数静态变量可以同名
花括号表达式
宏AAA的值等于最后一个表达式++a的值,也就是2;
sizeof(array)
若array是数组名,则sizeof就是数组的size
变量长度
printf函数
%.2x 该格式表示至少以2位16进制数表示制定参数
逻辑右移与算术右移
逻辑右移:高位补0;
算术右移:高位补原高位。如:10001010 >> 4,变成11111000,又如00110110 >> 4,变成00000011
一般来说,计算机都支持这两种右移。但这就造成一个移植性问题,当遇到这种表达式时,究竟是解释成哪种右移方式。实际上,几乎所有编译器/计算机组合都使用算术右移。可以看到,这种右移方式在有符号整数情况时比较有用。但有个情况要记住:-1 不管算术右移几位都是-1。
参考:《深入理解计算机系统》 2.1.10
补码
计算机都是以二进制补码形式表示一个整数,怎么转换无符号/有符号整数呢,有一个口诀:按位取反加一
如:1为0000 0001,-1为1111 1111。它们互为各自的按位取反加一。这里有个问题-1为什么是1111 1111,因为-1加1是0,只有1111 1111这种形式加1才会是0。
有符号字符型整数的范围是-128~127,其实不管是8位、16位或32位,负数都比整数多1,是什么原因。以8位举例,在无符号数时原本1000 0000是128,但在有符号数时确实-128,这就是原因。
前面只说了有符号十进制整数转化为二进制口诀,而有符号二进制整数转化为十进制计算如下:
以1110为例,计算为:-1 * 2 ^ ( 3) + 1 * 2 ^ (2) + 1 * 2 ^ (1) + 0 * 2 ^ (0) = -8 + 4 + 2 = -2
参考:《深入理解计算机系统》 2.2.3
const修饰符
简单说,如果有个常量要使用,又不想用宏定义(显得乱,且永远占空间),则用const变量是一种选择,以用来提醒,这个值它就是一个常量,如果错误给它赋值了,请编译器帮忙提示出错。
宏定义
#define CONVERT(base) __CONVERT(#base)//#base会展开成"base"
#if defined (__vax__) || defined (__ns16000__)
当要对两个宏进行判断时,可用以上形式
#define DEBUG_PRINTF(s, ARGS...) printf(s, ##ARGS)
可以重复定义宏,后定义的会覆盖先定义的
运算符优先级
typedef int *PINT
有一本书说的好,typedef类似于变量定义,只不过把变量名换成类型名。
上面例子可以这样记忆:定义一个指针类型PINT,其指向int。以前老是忘记的typedef用法,立即跟变量定义联系上,恐怕想忘都忘不了。
不过有特例:typedef int(pFunc)(char *, int);定义了一个函数类型pFunc,其指向一个返回值为int型、参数为char指针、int型的函数。
介绍下这本书:<<深入理解计算机系统>>,很适合初学者又有心进阶的人,正在缓慢学习中
typeof(x)
按照gcc man手册说法,这是gcc的特性,就像asm一样,不过有些标准不支持这些特性,如:在选项中加上-ansi或-std=c90后这些特性不生效(没试过)。
用法:
int i; typeof(i) n = 0; typeof(int) m = 1;
以上都表示int这个类型。
在内核的typecheck.h和module.h中都可以看到这种用法。
1UL 等于1ul
常量后面的后缀大小写通用
数组的特殊初始化方式
int ai[] = {[0] = 1, [1] = 2};这里初始化了第1、2两个成员。
嵌套宏的前后顺序无特定要求
#define SC_CLK_SET(addr, x) do{ WriteReg32(addr, (x));} while(0) #define WriteReg32(addr,data) (*(volatile unsigned long *)(addr)=(data))
前面的调用后面的,不会报错(其实只是替换,在.c程序前面能找到这个宏可以替换就不会报错)
但假如不是嵌套宏,那前后顺序有要求
break只能跳出一层
for (;;) { while (1) { printf("Inside while\n"); if (wh++ > 5) { break; } } printf("Inside for\n"); break; } printf("Outside for\n");
每个break只能跳出当前循环
strtol(const char *nptr, char **endptr, int base)
当输入字符串nptr含有16进制数,需要致命base为16
不同函数静态变量可以同名
花括号表达式
#define AAA ({int a = 1; ++a;})
宏AAA的值等于最后一个表达式++a的值,也就是2;
sizeof(array)
若array是数组名,则sizeof就是数组的size
变量长度
printf函数
%.2x 该格式表示至少以2位16进制数表示制定参数
逻辑右移与算术右移
逻辑右移:高位补0;
算术右移:高位补原高位。如:10001010 >> 4,变成11111000,又如00110110 >> 4,变成00000011
一般来说,计算机都支持这两种右移。但这就造成一个移植性问题,当遇到这种表达式时,究竟是解释成哪种右移方式。实际上,几乎所有编译器/计算机组合都使用算术右移。可以看到,这种右移方式在有符号整数情况时比较有用。但有个情况要记住:-1 不管算术右移几位都是-1。
参考:《深入理解计算机系统》 2.1.10
补码
计算机都是以二进制补码形式表示一个整数,怎么转换无符号/有符号整数呢,有一个口诀:按位取反加一
如:1为0000 0001,-1为1111 1111。它们互为各自的按位取反加一。这里有个问题-1为什么是1111 1111,因为-1加1是0,只有1111 1111这种形式加1才会是0。
有符号字符型整数的范围是-128~127,其实不管是8位、16位或32位,负数都比整数多1,是什么原因。以8位举例,在无符号数时原本1000 0000是128,但在有符号数时确实-128,这就是原因。
前面只说了有符号十进制整数转化为二进制口诀,而有符号二进制整数转化为十进制计算如下:
以1110为例,计算为:-1 * 2 ^ ( 3) + 1 * 2 ^ (2) + 1 * 2 ^ (1) + 0 * 2 ^ (0) = -8 + 4 + 2 = -2
参考:《深入理解计算机系统》 2.2.3
const修饰符
简单说,如果有个常量要使用,又不想用宏定义(显得乱,且永远占空间),则用const变量是一种选择,以用来提醒,这个值它就是一个常量,如果错误给它赋值了,请编译器帮忙提示出错。
宏定义
#define CONVERT(base) __CONVERT(#base)//#base会展开成"base"
#if defined (__vax__) || defined (__ns16000__)
当要对两个宏进行判断时,可用以上形式
#define DEBUG_PRINTF(s, ARGS...) printf(s, ##ARGS)
可以重复定义宏,后定义的会覆盖先定义的
运算符优先级