C语言不完全类型、延迟定义

问题

今天看到《自制编程语言》里面的提到这个不完全类型,我还真不知道

细节

大概是这样的,不让别人知道我们代码内部实现细节

比如我们实现一个栈,我们把数据结构的定义放在头文件里面,然后别人include我们头文件的时候(并添加.o),就能看到具体细节,比如可能就会主动操作里面的num或者array,破坏封装性

#ifndef STACK_H
#define STACK_H
typedef struct Stack{  
    int num;
    int array[MAX_N];
}Stack;
#endif

实现

按照如下实现就不会有这样的问题

//stack.h
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#ifndef STACK_H
#define STACK_H
typedef struct MyStack Stack;  
Stack *createStack();  
void destroyStack(Stack **s);  
int push(Stack **s, int w);  
int isEmpty(Stack **s);  
int pop(Stack **s);  
#endif
//stack.c
#include "stack.h"

#define MAX_N  100

typedef struct MyStack_tag{  
    int num;
    int array[MAX_N];
    struct MyStack *node; 
}MyStack;

Stack *createStack() {  
    MyStack *s = (MyStack *)malloc(sizeof(MyStack));
    return (Stack *)s;
}

void destroyStack(Stack **s) {  
    MyStack *stack = (MyStack *)*s;
    free(stack);
    *s = NULL;
    stack = NULL;
}

int push(Stack **s, int w) {  
    MyStack *stack = (MyStack *)*s;
    if(stack->num + 1 <= MAX_N) {
        stack->array[stack->num++] = w;
        return 1;
    }
    return 0;
}

int isEmpty(Stack **s) {  
    MyStack *stack = (MyStack *)*s;
    if(0 == stack->num) {
        return 1;
    }
    return 0;
}

int pop(Stack **s) {  
    MyStack *stack = (MyStack *)*s;
    if(0 == stack->num) {
        return 0;
    }
    return stack->array[--stack->num];
}

int getLen(Stack **s) {  
    MyStack *stack = (MyStack *)*s;
    return stack->num;
}
//main.c
#include "stack.h"
#include <stdio.h>
#include <stdlib.h>

int main() {  
    Stack *s = createStack();
    push(&s, 2);
    printf("%d\n", pop(&s));
    destroyStack(&s);
}

大概逻辑是这样的,我们自己的库:

头文件typedef struct MyStack Stack;还有各种对外的接口函数

cpp文件:有详细对自己内部MyStack的定义,可见Mystack,也可见Stack,内部实现的用Stack结构体

外部调用#include头文件,调用跟Stack相关接口,这里注意,因为main.c里面,Stack是延迟定义的,所以不能使用sizeof等等,也就是说不能直接使用malloc Stack;而且main.cMyStack不可见,不能使用MyStack

其他语言

面向对象语言中不叫“延迟定义”。而是叫封装、访问权限、接口和多态。类的封装和访问权限可以阻止客户访问类的实现细节,而接口和多态可以隐藏实现细节。

其他说明

Linux C编程一站式学习上面的

C语言的类型分为函数类型、对象类型和不完全类型三大类。对象类型又分为标量和非标量类型。不完全类型是暂时没有完全定义好的类型,编译器不知道这种类型该占几个字节的存储空间。具有不完全类型的变量可以通过多次声明组合成一个完全类型。不完全类型的结构体有重要作用:

struct  s{

        char  data[6];

       struct  s  *next;

};

当编译器处理到第一行struct s{ 时,认为struct s{是一个不完全类型,当处理到第三行struct s *next;时,认为next是一个指向不完全类型的指针,当处理到第四行};时struct s成了一个完全类型,next也成了一个指向完全类型的指针。但不可再结构体内定义struct s next,因为它不知道next将占用几个字节,所以结构体可以递归的定义指针成员但不可以递归的定义变量成员


C语言不完全类型与延迟定义

读《Linux C编程一站式学习》I