C专家编程--随记(二)

第三章------声明

一.声明的构成

1.声明器就是由标识符以及与它组合在一起的任何指针、函数括号、数组下标等组成。

2.结构:一种把一些数据项组合在一起的数据结构
(1)

struct tag{
    short dd;
    int aa;
}my_tag;
//tag--->结构类型名
//my_tag--->结构变量
struct tag my1_tag;
my_tag my2_tag;
//以上两种都等价

(2) 允许存在位段。无名字段以及字对齐所需的填充字段。(类型为int,unsigned int,signed int 或加上限定符)

struct pid{
    unsigned int inactive : 1;  //一个位的填充
    unsigned int          : 0;  //填充到下一个边界
}

3.联合:可称变体记录,外表与结构相似,所有成员都是从偏移位置零开始存储,每个成员重叠在一起,在某一时刻只有一个成员真正存储于该地址。
tips:
(1)联合一般用于节省空间,有些数据项不可能同时出现,但同时存储则浪费内存;
(2)可以把两个互相排斥的字段存储于一个联合中来节省空间。
(3)联合可以把同一个数据解释成两种不同的东西.

union bits32{
    int whole;    //一个32位的值
    struct {char c0,c1,c2,c3;}byte;  //4个8位的字节
}

4.枚举:把一串名字与一整串整型值联系在一起

enum sizes{small = 7 ,mdedium,big=10,large};

tips:
(1)一般情况从0开始,赋值的标识符,后一个值比前一个大1
(2)与#define相比,编译时枚举名字一直在调试器中可见,而宏定义则编译就丢弃

二.优先级规则
步骤解释
A首先,声明从标识符名字读取,并注意到它直接被括号括住
B优先级从高到低是
B1声明中被括号的那部分
B2后缀操作符:括号()表示这个是一个函数 , 挎号[ ]表示这个是一个数组
B3前缀操作符:* 表示指向…的数组
C如果const 或volatile 关键字的后面紧跟类型说明符(如 int等),那么将它用于类型说明符。其它情况下,const或volatile 关键字作用于它左边紧邻的指针星号

eg:
(1)

char *const*(*next)();
//A,先看变量next,翻译成next是...
//B1,看它是被扩号括住,观察里面有*,翻译成next是一个指向...的指针
//B2,后面是一个括号,说明next是一个函数指针,指向一个返回...的函数
//B3,前缀是一个*,表示得出指针所指的内容
//C,char * const是一个整体,解释为:指向字符的常量指针
//next是一个指针,它指向一个函数,函数返回另一个指针,
//这个指针指向类型为char的常量指针

(2)

char *(*str[10])(int **p);
//A,找到str变量名,str是...
//B1,被括号括住,后缀有[],所以str是一个元素数量为10的数组
//B3,前缀是一个*,所以str是一个数组,元素类型为指针,数量为10的数组
//B1,(*str[10])(),后面是一个括号,说明是str是一个数组,元素类型是函数指针
//且接受一个指向整型指针的指针
//B3,char *()() 解释为该函数返回一个指向字符型的指针
//str是一个数组,元素类型是一个函数指针,接受一个指向整型指针的指针,
//并且返回一个指向字符型的指针
三.typedef

1.typedef:为一种类型引入新的名字,而不是为变量分配空间!
tips:不要在一个typedef放入多个声明类型,并且也不要把它放在声明的中间
2.typedef 与#define 的区别
(1)可以用其他类型说明符对宏类型名进行拓展,而typedef所定义的类型名就不能

#define peach int
typedef int apple
unsigned peach i; //正确
unsigned apple b;  //error!!

(2)在连续几个变量的声明中,typedef定义的类型可以保证声明中所有的变量均为同一种类型,而用#define则无法保证

#define int_ptr int*
int_ptr chalk , cheese;
//上行经宏拓展后变成
int * chalk , cheese;
//前者为int * ,后者为int
**********************************
**********************************
typedef int * int_ptr
int_ptr chalk , chesse;
//两者都是 int *

3.typedef的使用提示

(1)不要为了方便起见对结构使用typedef
(2)它应该用在数组、结构、指针以及函数的组合类型
(3)可移植类型
(4)也可以为后面的强制类型转换提供一个简单的名字

四.程序:将C语言的声明翻译成通俗语言
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define MAXTOKENS 100
#define MAXTOKENLEN 64

//把C语言声明翻译成通俗语言 
//数据结构是堆栈,从左向右读取,把各个标记依次压入堆栈,直到遇到标识符。然后继续向右读入一个标记,
//也就是标识符右边的标记,接着,再把标识符左边的标记从堆栈中弹出 

enum	type_tag {IDENTIFIER , QUALIFIER,TYPE};
//identifier 取标记
//type		类型
//qualifier	限定符 
struct token{
	char type;
	char string[MAXTOKENLEN];
};
m

int top = -1;
struct token stack[MAXTOKENS];
struct token this;

#define pop stack[top--]
#define push(s) stack[++top] = s


//推断 标识符的类型 
enum type_tag classify_string(void)
{
	char *s = this.string;
	if(!strcmp(s,"const")){
		strcpy(s,"read-only");
		return QUALIFIER;
	}
	if(!strcmp(s,"volatile"))	return QUALIFIER;
	if(!strcmp(s,"void"))	return TYPE;
	if(!strcmp(s,"char"))	return TYPE;
	if(!strcmp(s,"signed"))	return TYPE;
	if(!strcmp(s,"unsigned"))	return TYPE;
	if(!strcmp(s,"short"))	return TYPE;
	if(!strcmp(s,"int"))	return TYPE;
	if(!strcmp(s,"long"))	return TYPE;
	if(!strcmp(s,"float"))	return TYPE;
	if(!strcmp(s,"double"))	return TYPE;
	if(!strcmp(s,"struct"))	return TYPE;
	if(!strcmp(s,"union"))	return TYPE;
	if(!strcmp(s,"enum"))	return TYPE;
	return IDENTIFIER;
}

//读取下一个标记到“this”,取标记 
void gettoken(void)
{
	char *p = this.string;
	
	//省略空白字符
	while((*p = getchar()) == ' ');
	
	if(isalnum(*p)){
		//读入的标识符以A-Z,0-9开头
		while(isalnum(*++p = getchar()));
		ungetc(*p, stdin);	// int ungetc(int char, FILE *stream) 把字符 char(一个无符号字符)
							//推入到指定的流 stream 中,以便它是下一个被读取到的字符。
		*p = '\0';
		this.type = classify_string();
		return; 
	}
	
	if(*p == '*'){
		strcpy(this.string , "pointer to");
		this.type = *p;
		return;
	}
	this.string[1] = '\0';
	this.type = *p;
	return;
}

//理解所有分析过程的代码段
//先调用gettoken,把标记压入堆栈,直到遇见第一个标识符
//printf“该标识符是....”,this.string
//再继续调用gettoken 
read_to_first_identifer()
{
	gettoken();
	while(this.type != IDENTIFIER){
		push(this);
		gettoken();
	}
	printf("%s is ",this.string); //标识符是什么... 
	gettoken();
} 

deal_with_arrays(){
	while(this.type == '['){
		printf("array ");
		gettoken(); //数字或者]
		if(isdigit(this.string[0])){
			printf("0..%d ",atoi(this.string)-1);
			gettoken();//读取] 
		}
		gettoken(); //读取完]后再做一个标记
		printf("of "); 
	}
}

deal_with_function_args()
{
	while(this.type != ')'){
		gettoken();
	}
	gettoken();
	printf("function returning ");
}

deal_with_pointers()
{
	while(stack[top].type == '*'){
		printf("%s ",pop.string);
	}
}

deal_with_declarator()
{
	//处理标识符之后可能存在的数组或函数
	switch(this.type){
		case '[' : deal_with_arrays();
					break;
		case '(' : deal_with_function_args();
	} 
	
	deal_with_pointers();
	
	//处理在读入到标识符之前压入堆栈中的符号
	while(top >= 0){
		if(stack[top].type == '('){
			pop;
			gettoken();//读取')'之后的符号
			deal_with_declarator(); 
		}else{
			printf("%s ",pop.string);
		}
	} 
}

main()
{
	//将标记压入堆栈,直至遇见标识符
	read_to_first_identifer();
	deal_with_declarator();
	printf("\n");
	return 0; 
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值