C语言中的声明

文章目录

  • C 语言中的定义
  • C 语言中的声明
    • 声明
    • 复杂的声明
  • 使用typedef
  • 一个小程序


C 语言中的定义

定义:只能出现在一个地方,用于确定对象类型和分配内存空间。
声明:可以在不同文件中多次出现,用于向编译器描述对象类型。

所以char string[10]的写法是定义,而extern char string[10]是声明

C 语言中的声明

声明

类型说明符(type-specifier),存储类型(storage-class),类型限定符(type-qualifier)

  • 类型说明符(type-specifier):如void、char、short、int、结构体类型、枚举类型等
  • 存储类型(storage-class):如数组的[]、指针的*和函数的()
  • 类型限定符(type-qualifier):如const、volatile、restrict

复杂的声明

如果你想研究一下Linux的内核源码,你会看到如下的声明

void*(*(*fp1)(int))[10]
float(*(*fp2)(int,int,float))(int)
typedef double (*(*(*fp3)())[10])()
int (*(*fp4())[10])()

哦,或者在《C陷阱与指针》中有(*(void(*)())0()这样的一个声明,我记得作者给出的解释是:在有些MCU(micro control unit),程序需从0地址处执行,(*(void(*)())0()这个东西便可使运行0地址处的指令(注意:这种方法类似于空指针,看来很危险,别轻易尝试)

  • 如何分析复杂声明

《C陷阱与指针》给出了左右法则:

The right-left rule: Start reading the declaration from the innermost parentheses, go right, and then go left. When you encounter parentheses, the direction should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declaration has been parsed.

意思就是:

从最里面的圆括号(或者用户的变量名)开始读取声明,先向右,然后向左。当遇到括号时,应该颠倒方向(向左)。一旦括号中的所有内容都解析完毕,就可以跳出括号。继续以上操作,直到解析完整个声明。


使用typedef

你听说过signal()函数吗?即系统产生特定软中断时会调用的函数。
在ANSI C标准中,其函数原型为void (*signal(int sig, void(*func)(int)))(int)
现在使用typedef简化为typedef void(*ptr_func) (int)ptr_func signal(int ,ptr_func)

  • typedef 与 define 的区别
#define int* int_ptr
int_ptr pointer1, pointer2;
/* int * pointer1, pointer2 */

在这里pointer2并未被声明为int*类型,而是int类型

typedef int* int_ptr;
int_ptr pointer1, pointer2;

这样就没有问题了

  • 在使用typedef时的一些建议

    • 非常推荐在声明数组、结构体、枚举、联合体、函数、指针时使用
    • 推荐不要省略结构标签(但其实很多库并未遵守)因为使用结构体标签可使代码更为清晰
typedef struct my_tag {
    int variable1;
    int variable2;
}my_type;
my_type struct_variable1, struct_variable2;

一个小程序

这是一个能解析C语言声明的小程序。

#include 
#include 
#include 
#include 

/*宏定义*/
#define MAXTOKENS     100
#define MAXTOKENLEN   64
#define pop           stack[top--]
#define push(s)       stack[++top]=s

/*自定义类型*/
enum type_tag {
    IDENTIFIER, 
    QUALIFIER,
    TYPE,
};

struct token
{
    char type;
    char string[MAXTOKENLEN];
};

/*函数声明*/
enum type_tag classify_string(void);
void gettoken(void);
void read_to_first_identifier(void);
void deal_with_arrays(void);
void deal_with_function_args(void);
void deal_with_pointers(void);
void deal_with_declarator(void);

/*全局变量*/
int top = -1;
struct token stack[MAXTOKENS];
struct token this;

int main() {
    read_to_first_identifier();
    deal_with_declarator();
    printf("\n");
    return 0;
}

/*函数具体实现*/
/* 识别this.string字符串是否为关键字 */
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;
}

/* 获得用户输入,并忽略空格 */
void gettoken(void) {
    char* p = this.string;
    while((*p = getchar()) == ' '); /*忽略空格*/
    if(isalnum(*p)) {
        while(isalnum(*++p = getchar()));
        ungetc(*p, stdin);
        *p = '\0';
        this.type = classify_string();
        return ;
    }
    if(*p == '*') {
        strcpy(this.string, "\033[32mpointer \033[37mto");
        this.type = '*';
        return ;
    }
    this.string[1] = '\0';
    this.type = *p;
    return ;
}

/* 获得用户的变量名 */
void read_to_first_identifier() {
    gettoken();
    while(this.type != IDENTIFIER) {
        push(this);
        gettoken();
    }
    printf("\033[35m%s\033[37m is ", this.string);
    gettoken();
}

/* 处理数组类型 */
void deal_with_arrays() {
    while(this.type == '[') {
        printf("\033[34marray ");
        gettoken();
        if(isdigit(this.string[0])) {
            printf("0..%d ", atoi(this.string)-1);
            gettoken();
        }
        gettoken();
        printf("\033[37mof ");
    }
}

/* 处理函数类型 */
void deal_with_function_args() {
    while(this.type != ')') {
        gettoken();
    }
    gettoken();
    printf("\033[33mfunction \033[37mreturning ");
}

/* 处理指针类型 */
void deal_with_pointers() {
    while(stack[top].type == '*') {
        printf("%s ", pop.string);
    }
}

/* 分辨函数、指针、数组等类型 */
void 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);
        }
    }
}







                                     ------ By Flier

2024.1.29

你可能感兴趣的:(#,C语言,c语言,开发语言)