本文为个人读书笔记,仅供记录学习过程中遇到的日后需要留意的问题,如有相关版权问题请及时通知作者。
这是我非常喜欢的一本书,讲了很多其他著名C语言书籍都没有提到过的细节问题,希望对C语言有兴趣的朋友去读一读。好像并没有出版,晚上可以找到PDF版。
register
register变量必须是能被CPU寄存器所能接受的类型,必须是一个单个的值,且其长度应小于或等于整型的长度。
register变量可能不存放在内存中,所以不能用取址运算符
static
静态全局变量,作用域仅限于变量被定义的文件中,从定义处到文件结尾。其他文件使用extern声明也无法使用。
静态局部变量,在函数体内定义,只能在函数内使用。函数运行结束,静态变量值不会被销毁,函数下次使用时仍然能用到这个值。
静态函数,函数的作用域限于本文本,所以这种函数又称为内部函数。使用内部函数的好处是,不同的人编写不同的函数时,不用担心自己定义的函数会与其它文件中的函数同名。
变量的命名规则
尽量避免名字中出现数字编号
多个文件之间共同使用的全局变量或函数要加范围限定符(dbo_ )
if else
bool与零值判断最好的写法:if(bTestFlag) if(!bTestFlag)
float与零值判断最好的写法:if((fTestVal>=-EPSINON)&&(fTestVal<=EPSINON));//EPSINON为定义好的精度
指针与零值判断最好的写法:if(NULL==p); if(NULL!=p);
建议在真正需要用空语句时写成:NULL;
switch case
即使不需要default处理,也应该保留一个空的default语句。
尽量把正常情况,执行频率高的case放在前面
default子句只用于检查真正的默认情况,而不要把剩下的一种情况放到case里。
循环
尽量把长循环放在内层,短循环放在外层
尽量不在for内修改循环变量
循环尽量控制在3层以内
goto
禁用。
void
void * 可以指向任何类型的数据,同为void型的指针之间可以互相赋值
如果没有返回值的函数,应声明为void类型。C语言中,不加返回值类型限定的函数,就会被编译器作为返回整形值处理。
ANSI标准中,不能对void 指针进行算法操作(+-)。GNU中作为char *进行计算。
void不能代表一个真实的变量,只是一种抽象。
return
return语句不可返回指向“栈内存”的指针,因为该内存在函数体结束时被自动销毁
const
const修饰只读变量,而不是常量
const只读变量必须在定义的同时初始化
#define宏是在预编译阶段进行替换,而const修饰的制度变量是在编译的时候确定值。#define宏没有类型,而const修饰的只读变量具有特定的类型。
const int *p; | const修饰*p,p是指针可变,*p是指针指向的对象不可变。 |
int const *p; | const修饰*p,p是指针可变,*p是指针指向的对象不可变。 |
int *const p; | const修饰p,p不可变,p指向的对象可变 |
const int *const p; | 前一个const修饰*p,后一个const修饰p,指针p和p指向的对象都不可变。 |
const修饰函数参数,防止参数值被参数体改变。
const修饰函数返回值,保证返回值不可被改变。
volatile
修饰的变量表示可以被某些编译器的未知元素更改(程序代码意外的元素)
volatile可以保证对特殊地质的稳定访问。
extern
struct
结构体所占的内存大小是其成员所占内存之和。
空结构体的大小是1个byte
C99中,结构中的最后一个元素允许时未知大小的数组,叫做柔性数组成员,但结构中的肉型数组成员前必须至少一个其他成员。包含柔性数组成员的结构用malloc()函数进行内存动态分配,分配的内存应该大于结构的大小,以适应柔性数组与其大小。用完后需要用free函数释放内存。柔性数组不算结构体的正式成员。
C++里struct与class一般可以通用,区别在于struct成员默认public,class默认private
union
如果一些数据不可能在同一时间同时被用到,则可以使用union
数据存储模式:大端模式:字数据的高字节存储在地地址中,低字节存放在高地址中。小端模式:字数据的高字节接存储在高地址中,而字数据的低字节则存放在低地址中。
union型数据所占的空间等于其最大的成员所占的空间。对union型的成员的存取都是相对于该联合体基地址的偏移量0开始。
可以利用union类型数据的特点,判断数据模式是大端模式还是小端模式。
enum
实际上enum是对一个变量取值范围的限定,花括号内是取值范围,如果赋给该类型变量的值不再列表中,则会报错或警告。
与#define宏的区别:#define宏常量是在预编译阶段进行简单替换。枚举常量则是在编译的时候确定值。
typedef
typedef是给一个已经存在的数据类型(而不是变量)取一个别名,而非定义一个新的数据类型。
typedef不支持类型扩展(unsigned),但支持const