> ## Content Index
> Fetch the complete content index at: https://blog.hacking.pub/llms.txt
> Use this file to discover other available public pages before exploring further.

# C语言不完全类型、延迟定义
- URL: https://blog.hacking.pub/2017/03/22/cyu-yan-bu-wan-quan-lei-xing-yan-chi-ding-yi/
- Published: 2017-03-22T03:50:44.000Z
- Updated: 2017-03-22T04:00:17.000Z
- Author: chainhelen
- Tags: 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.c`对`MyStack`不可见，不能使用`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语言不完全类型与延迟定义](http://blog.csdn.net/candcplusplus/article/details/38498707?utm%5Fsource=tuicool&utm%5Fmedium=referral)  
[读《Linux C编程一站式学习》I](http://www.xuebuyuan.com/2230469.html?ref=blog.hacking.pub)