首页 > 技术文章 > C语言深度剖析笔记

actionke 2015-01-15 10:04 原文

register
register 变量必须是一个单个的值,并且其长度应小 于或等于整型的长度。 而且 register 变量可能不存放在内存中,所以不能用取址运算符“&” 来获取 register 变量的地址。
 
float 变量与“零值”进行比较
if((fTestVal >= -EPSINON) && (fTestVal <= EPSINON)); //EPSINON 为定义好的 精度。
 

volatile

volatile 关键字告诉编译器 i 是随时可能发生变化的,每次使用它的时候必须从内存中取出 i 的值,因而编译器生成的汇编代码会重新从 i 的地址处读取数据放在 k 中。

这样看来,如果 i 是一个寄存器变量或者表示一个端口数据或者是多个线程的共享数 据,就容易出错,所以说 volatile 可以保证对特殊地址的稳定访问。

 
extern

extern 可以置于变量或者函数前,以 标示变量或者函数的定义在别的文件中,下面的代码用到的这些变量或函数是外来的,不 是本文件定义的,提示编译器遇到此变量和函数时在其他模块中寻找其定义

 
空结构体占用空间大小

struct student {
}stu;

sizeof(stu)的值是多少呢?
Visual C++ 6.0上为 1
编译器认为你构造一个结构体数据类型是用来打包一些数据成员的,而最小的数据成员需要 1 个 byte,编译器为每个结构体类型数据至少预留 1 个 byte 的空间。所以,空结构体的大小就定位 1 个 byte。
 

struct 与 class 的区别

struct 的成 员默认情况下属性是 public 的,而 class 成员却是 private 的。
 
union 关键字
union 维护足够的空间来置放多个数据成员中的“一种”,而不是为每一个数据成员配置 空间,在 union 中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所 有的数据成员具有相同的起始地址。

union StateMachine

{
     char character;
     int number;
     char *str;
     double exp;

};

一个 union 只配置一个足够大的空间以来容纳最大长度的数据成员,以上例而言,最大 长度是 double 型态,所以 StateMachine 的空间大小就是 double 数据类型的大小。
另外,注意大小端模式对 union 类型数据存储的空间有影响
 
typedef 关键字

typedef struct student
{

     //code
}Stu_st,*Stu_pst;
A),struct student stu1;和 Stu_st stu1;没有区别。
B),struct student *stu2;和 Stu_pst stu2;和 Stu_st *stu2;没有区别。 这个地方很多初学者迷惑,B)的两个定义为什么相等呢?其实很好
 
const
const int *p;      //p指向的对象不可变(*p不可变)
int const *p;     //p指向的对象不可变(*p不可变)
int *const p;     //p不可变,p指向的对象可变
const int *const p; //前一个 const 修饰*p,后一个 const 修饰 p,指针 p 和 p 指向的对象 都不可变
 
void Fun(const int i);     //不希望这个参数值被函数体内意外改变。
const int Fun (void);     //返回值不可被改变。
 
#运算符
 
SQR(8)
输出的是:
The square of 8 is 64.
 

##预算符

##运算符可以用于宏函数的替换部分。这个运算符把两个语言符号组 合成单个语言符号。
#define XNAME(n) x ## n

如果这样使用宏:

XNAME(8)

则会被展开成这样:

x8

 
指针和数组
A),int* p1[10];     // 指针数组,数组的每个值都是指针
“[]”的优先级比“*”要高。p1 先与“[]”结合,构成一个数组的定义,数组名为 p1,int * 修饰的是数组的内容,即数组的每个元素。那现在我们清楚,这是一个数组,其包含 10 个 指向 int 类型数据的指针,即指针数组。
B),int  (*p2)[10];     //数组指针,可以理解为 int (*)[10] p2,实际上就是二维数组p[][10];
“()”的优先级比 “[]”高,“*”号和 p2 构成一个指针的定义,指针变量名为 p2,int 修饰的是数组的内容, 即数组的每个元素。数组在这里并没有名字,是个匿名数组。那现在我们清楚 p2 是一个指 针,它指向一个包含 10 个 int 类型数据的数组,即数组指针。
 
函数指针
A),char * fun3(char * p1,char * p2);     //fun3是函数名,p1,p2是参数,其类型为char*型,函数的返回值为char * 类型。
B),char * *fun2(char * p1,char * p2);     //与 C)表达式相比,唯一不同的就是函数的返回值类型为 char**
C),char * (*fun1)(char * p1,char * p2);     //fun1 不是什么函数名,而是一个 指针变量,它指向一个函数。这个函数有两个指针类型的参数,函数的返回值也是一个指 针。我们把这个表达式改写一下:char * (*)(char * p1,char * p2) fun1; 这样子是不 是好看一些呢?只可惜编译器不这么想。
 
函数指针数组
char * (*pf)(char * p)     //函数指针
char * (*pf[3])(char * p);     //这是定义一个函数指针数组。它是一个数组,数组名为 pf,数组内存储了 3 个指向函数的 指针。pf是数组名
 
函数指针数组的指针
char * (*(*pf)[3])(char * p);     //pf是指针,这个指针指向一个包含了 3 个元素的数组;这个数字里 面存的是指向函数的指针;这些指针指向一些返回值类型为指向字符的指针、参数为一个 指向字符的指针的函数。
 

推荐阅读