合法:
pag60 (段位)
struct pid_tag
{
unsigned int inactive : 1;
unsigned int : 1; (一个位的填充)
unsigned int refcount : 6;
unsigned int : 0; (填充到下一字边界)
short pid_id;
struct pid_tag *link;
}
位段的类型必须是,int,unsigned int, signed int(或加上限定符)。
------------------------------pag61 (参数传递)
参数传递首先尽可能地存放在寄存器中,不够了再存在堆栈中。
一个int型参数一般会被传递到寄存器中,而结构参数则很可能被传递到堆栈中。
------------------------------pag62 (联合)
在联合中所有的成员都从偏移地址0开始存储。这样每个成员的位置重叠在一起:在某一时刻,只有一个成员真正存储于该地址。(联合大小为最大的那个元素大小)。
union bits32_tag
{
int whole;
struct {char c0, c1, c2, c3;} byte;
} value;
这个联合允许程序员提取整个32位值(作为int),也可以提取单独的字节段如value.byte.c0。
------------------------------pag64 (c声明优先级)
A 声明从他的名字开始读取,然后按照优先级顺序依次读取。
B 优先级从高到低依次是:
B1 声明中被括号括起来的那部分
B2 后缀操作符:
括号()表示这个一个函数,而放括号[]表示这是一个数组
B3 前缀操作符:星号*表示“指向。。。的指针”
C 如果const和volatile关键字的后面紧跟着类型说明符(如int,long等),他作用于类型说明符。在在其他情况下,const和volatile关键字作用域他左边紧邻的指针星号。
例:
char * const *(* next)();
A 首先,看变量名“next”,并注意到他直接被括号所括住
B1 所以先把括号里的东西作为一个整体,得出“next是一个指向...的指针”
B 然后考虑括号外面的东西,在星号前缀和括号后缀之间作出选择
B2 B2规则告诉我们优先级较高的是右边的函数括号,所以得出“next是一个函数指针,指向一个返回...的函数”
B3 然后,处理前缀“*”,得出指针所指的内容
C 最后,把“char *const”解释为指向字符的常量指针
结果:
next是一个指针,他指向一个函数,该函数返回另一个指针,该指针指向一个类型为char的常量指针。
------------------------------pag68 (typedef和#define)
1、可以用其他类型说明符对宏类型名进行扩展,但对typedef所定义的类型名却不能这样做
#define peach int
unsigned peach i; //合法
typedef int banana;
unsigned banana i;//非法
2、在连续几个变量的声明中,用typedef定义的类型能够保证声明中所有变量为同一类型,#define只有第一个
------------------------------pag71(typedef应该用在:)
1、数组、结构、指针以及函数的组合类型
2、可移植类型。如 typedef unsigned int int16_t;移植时只要在typedef中修改就可以
------------------------------pag83(声明数组时的长度)
由于并未在声明中为数组分配内存,所以并不需要提供关于数组长度的信息。对于多维数组,需要提供最左边一维之外其他维的长度---这就给编译器足够的信息产生相应的代码。
------------------------------pag85(数组指针差异)
extern char *p;
p[3];
编译器:
1、取得符号表(.symtab)(存放定义和引用的函数和全局变量信息)中指针p的地址,提取存储于此处的值(地址)
2、把下标表示的偏移量与地址值相加,产生另一个地址
3、访问上面这个地址,取得字符
之所以会如此,是因为我们告诉编译器我们拥有的是一个指针。
但是只有当p原来定义为指针时这个方法才是正确的。
文件a.c
char p[10]; (p中是字符)
文件b.c
extern char *p; (p中是地址)
p[i];
当用p[i]这种形式提取这个声明的内容时,实际上得到的是一个字符。但编译器按照上面的3个步骤,却把他当成是一个指针!
加上点我自己的理解:
第二个例子和常见的函数中实参传递给形参的拷贝值并不一样,上面这样相当于把*p和p[10]等同了,类似给文件a.c中的数组p加上了这样一个操作:(char *)p[0~9]。像上面第二中情况,因为编译器在编译阶段已经确认了p的类型,于是后面无法改变,链接时就出现了相应的问题。如果在像char *p = "abcd";p[3];这样出现在同一文件中,编译器编译时就知道p是一个指针,并按照指针的方式处理,不会把p当成数组名那样看成指针常量(就是地址值)直接加上3个元素的大小,然后取地址中的值,而是提取指针变量p中的值作为地址做相应操作。定义为指针时要比定义为数组时多一层提取!
所以跨文件时不要这样做,数组就声明成数组,指针就声明成指针!