[
    [
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "操作系统课程设计指导书"
                    }
                ],
                "level": 1
            },
            "bbox": [
                258,
                205,
                744,
                241
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "赵伟华 刘真 张梅"
                    }
                ]
            },
            "bbox": [
                396,
                332,
                615,
                354
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "2017 年 08 月"
                    }
                ]
            },
            "bbox": [
                388,
                703,
                537,
                724
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "计算机学院"
                    }
                ]
            },
            "bbox": [
                401,
                741,
                529,
                760
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "第六章 linux 常用工具介绍"
                    }
                ],
                "level": 1
            },
            "bbox": [
                309,
                91,
                702,
                115
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "6.1 查看 linux 源码内容工具"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                147,
                505,
                166
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "学习linux的实现原理时，经常需要查看某些数据结构的定义格式、某些内核函数的具体实现过程等，相关工具比较多，这里介绍 ctags 和 source insight 两种。"
                    }
                ]
            },
            "bbox": [
                144,
                197,
                848,
                234
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "6.1 .1 通过相关网站查询"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                244,
                426,
                262
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "1.网址 1：http://lxr.linux.no/"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "2.网址 2：http://lxr.free-electrons.com/"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                179,
                282,
                537,
                335
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "6.1.2 vim "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\mathbf { + }"
                    },
                    {
                        "type": "text",
                        "content": "ctags "
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                357,
                369,
                372
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在 vim 中安装插件 ctags 后，就可以在终端方便地使用 vi 命令查看 linux 源码内容了。"
                    }
                ]
            },
            "bbox": [
                179,
                388,
                838,
                405
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. 安装 ctags 插件"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                414,
                337,
                432
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Ctags 插件的功能是遍历 linux 源码文件，为源码的变量/对象、结构体/类、函数/接口、宏等产生索引文件：tags 文件，以便快速定位这些内容。tags 文件也是 Taglist 和 OmniCppComplete工作的基础。"
                    }
                ]
            },
            "bbox": [
                144,
                447,
                848,
                504
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "有两种方法安装ctags 插件，一种是源码安装，一种是在ubuntu中使用apt-get安装。"
                    }
                ]
            },
            "bbox": [
                179,
                510,
                838,
                526
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1）ubuntu 中使用 apt-get 安装："
                    }
                ]
            },
            "bbox": [
                189,
                532,
                453,
                546
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "sudo apt-get install ctags "
                    }
                ]
            },
            "bbox": [
                226,
                554,
                458,
                569
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（2）下载源码安装："
                    }
                ]
            },
            "bbox": [
                189,
                575,
                342,
                590
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "1）从 http://prdownloads.sourceforge.net/ctags/ctags-5.8.tar.gz 下载 ctags源码包 ctags-5.8.tar.gz；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "或者从 http://ctags.sourceforge.net/下载 ctags 源代码包 "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "2）解压缩生成源代码目录；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "3）进入源代码目录，依次执行如下命令安装ctags："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                596,
                847,
                696
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "$ ./configure $ make $ sudo make install "
                    }
                ],
                "code_language": "shell"
            },
            "bbox": [
                250,
                702,
                423,
                760
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. 生成索引文件 tags"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                772,
                364,
                788
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "从终端进入linux 源码目录，执行："
                    }
                ]
            },
            "bbox": [
                181,
                803,
                458,
                819
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\$ 8"
                    },
                    {
                        "type": "text",
                        "content": "sudo ctags –R * "
                    }
                ]
            },
            "bbox": [
                215,
                825,
                381,
                840
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "“-R”标识递归创建，即包括 linux源代码根目录（当前目录）下的所有子目录；“*”表示所有文件。执行该命令后会在当前目录下生成一个“tags”文件，如图所示："
                    }
                ]
            },
            "bbox": [
                181,
                846,
                840,
                883
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "zwh@ubuntu:/usr/src/linux-4.4.19$ sudo ctags -R *\n[sudo] password for zwh:\nzwh@ubuntu:/usr/src/linux-4.4.19$ ls\narch crypto include kernel net security virt\nblock Documentation init lib README sound\ncerts drivers ipc MAINTAINERS REPORTING-BUGS tags\nCOPYING firmware Kbuild Makefile samples tools\nCREDITS fs Kconfig mm scripts usr\nzwh@ubuntu:/usr/src/linux-4.4.19$ "
                    }
                ],
                "code_language": "shell"
            },
            "bbox": [
                184,
                89,
                815,
                190
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如果只是在linux 源代码目录下查询源码信息，则不需要修改vim的配置文件；否则如果希望在其他路径下也能查看，则必须使用sudo vim /etc/vim/vimrc 编辑这个文件，方法是在vimrc文件中添加如下内容："
                    }
                ]
            },
            "bbox": [
                144,
                200,
                848,
                256
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "set tags=/usr/src/linux-4.4.19/tags; "
                    }
                ]
            },
            "bbox": [
                179,
                265,
                455,
                279
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "set autochdir "
                    }
                ]
            },
            "bbox": [
                181,
                286,
                287,
                298
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. 利用 ctags 文件查看 linux 源 码信息"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                311,
                509,
                326
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "最常用的命令有下面几个："
                    }
                ]
            },
            "bbox": [
                181,
                342,
                386,
                357
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1） "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\$ 8"
                    },
                    {
                        "type": "text",
                        "content": "vi –t tag："
                    }
                ]
            },
            "bbox": [
                189,
                363,
                342,
                378
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "命令中的“tag”是要查看的变量名、数据结构名、函数名等，如执行："
                    }
                ]
            },
            "bbox": [
                181,
                384,
                729,
                399
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\$ 8"
                    },
                    {
                        "type": "text",
                        "content": "vi –t effective_prio "
                    }
                ]
            },
            "bbox": [
                215,
                406,
                423,
                420
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "则会显示 effective_prio()的实现源码："
                    }
                ]
            },
            "bbox": [
                181,
                426,
                495,
                441
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "static int effective_prio(struct task_struct *p) { p->normal_prio = normal_prio(p); /* If we are RT tasks or we were boosted to RT priority, * keep the priority unchanged. Otherwise, update priority * to the normal priority: */ if (!rt_prio(p->prio)) return p->normal_prio; return p->prio; } "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                184,
                448,
                778,
                583
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（2） "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\operatorname { C t r l } + ]"
                    },
                    {
                        "type": "text",
                        "content": "命令"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                596,
                317,
                609
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在vim中，将光标移动到要查看的变量名、数据结构名、函数名处，同时按下“Ctrl+]”键，则立即跳转到光标所在变量名、数据结构名、函数名的定义处。"
                    }
                ]
            },
            "bbox": [
                144,
                615,
                838,
                652
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（3）Ctrl+T 命令"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                659,
                322,
                671
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在vim中同时按下“Ctrl+T”键，则返回查找或跳转到前一次界面处。"
                    }
                ]
            },
            "bbox": [
                179,
                678,
                722,
                694
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（4）ta命令"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                701,
                287,
                715
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在vim中命令行下使用 ta命令，也能显示变量名、数据结构名、函数名的定义，如："
                    }
                ]
            },
            "bbox": [
                181,
                721,
                836,
                736
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": ":ta normal_prio "
                    }
                ]
            },
            "bbox": [
                181,
                744,
                319,
                758
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "则显示 normal_prio()的定义："
                    }
                ]
            },
            "bbox": [
                181,
                764,
                416,
                778
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "static inline int normal_prio(struct task_struct *p) {\n    int prio;\n    if (task_has_DL_policy(p))\n        prio = MAX_DL_PRIO-1;\n    else if (task_has_rt_policy(p))\n        prio = MAX_RT_PRIO-1 - p->rt_priority;\n    else\n        prio = __normal_prio(p);\n    return prio;\n} "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                184,
                87,
                652,
                229
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "更多功能可通过命令 man ctags 或在 Vim 命令行下运行 help ctags 查询。"
                    }
                ]
            },
            "bbox": [
                194,
                239,
                709,
                254
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "6.1.3 安装使用 Taglist"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                285,
                415,
                300
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Taglist 是 vim的一个插件，提供源码的结构化浏览功能，可将源码中定义的函数、变量、结构体等以树结构显示，层次关系一目了然，便于快速定位查看。"
                    }
                ]
            },
            "bbox": [
                144,
                318,
                843,
                354
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1.安装 Taglist 插件"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                363,
                354,
                380
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "1）从 http://www.vim.org/scripts/script.php?script_id=273 下载安装包，也可以从http://vim-taglist.sourceforge.net/index.html 下载。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "2）以 root 用户进入/etc/vim 目录,将 Taglist 安装包复制到该目录下并解压，解压后会在当前目录下生成两个子目录：plugin 和 doc，如图所示："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                397,
                845,
                473
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "root@ubuntu:/etc/vim# unzip taglist_46.zip  \nArchive: taglist_46.zip  \ninflating: plugin/taglist.vim  \ninflating: doc/taglist.txt  \nroot@ubuntu:/etc/vim# ls  \ndoc plugin taglist_46.zip vimrc vimrc.tiny "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                223,
                476,
                631,
                546
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "3）进入/etc/vim/doc 目录，运行 vim，执行\"helptags\"命令。该命令是将 doc 下的帮助文档加入到 Vim 的帮助主题中，这样我们就可以通过在 Vim 中运行“help taglist.txt”查看 taglist 帮助。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "4）打开 vim的配置文件/etc/vim/vimrc，加入以下两行内容，则安装工作就完成了："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                555,
                847,
                611
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "let Tlist_Show_One_File "
                    },
                    {
                        "type": "equation_inline",
                        "content": "{ \\mathop { : = } } 1"
                    },
                    {
                        "type": "text",
                        "content": "//不同时显示多个文件的 tag，只显示一个"
                    }
                ]
            },
            "bbox": [
                248,
                617,
                801,
                632
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "let Tlist_Exit_OnlyWindow "
                    },
                    {
                        "type": "equation_inline",
                        "content": "^ { - 1 }"
                    },
                    {
                        "type": "text",
                        "content": "//taglist 为最后一个窗口时，退出 vim"
                    }
                ]
            },
            "bbox": [
                250,
                638,
                774,
                653
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Tlist_Sort_Type "
                    },
                    {
                        "type": "equation_inline",
                        "content": "="
                    },
                    {
                        "type": "text",
                        "content": "name //使 taglist 以 tag 名字进行排序"
                    }
                ]
            },
            "bbox": [
                250,
                661,
                668,
                675
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "还有许多其他的设置选项，请参考帮助文档:help taglist.txt。"
                    }
                ]
            },
            "bbox": [
                200,
                680,
                699,
                695
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2.使用 Taglist 插件"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                706,
                346,
                722
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1）在 vim 中打开 taglist 窗口："
                    }
                ]
            },
            "bbox": [
                184,
                736,
                480,
                751
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在vim命令方式下运行以下三个命令之一都可以打开 taglist窗口，如图所示："
                    }
                ]
            },
            "bbox": [
                179,
                756,
                793,
                772
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": ":Tlist :Tlist0pen :TlistToggle "
                    }
                ],
                "code_language": "autohotkey"
            },
            "bbox": [
                216,
                776,
                329,
                829
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/55f641d6940a3ce061008766baa1ba4c546250f525a465e8df10f9bd6ced8979.jpg"
                },
                "image_caption": [],
                "image_footnote": []
            },
            "bbox": [
                152,
                89,
                848,
                209
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "图中右边窗口是文件编辑窗口，左边是 taglist 窗口。在taglist窗口中分类显示右边文件中所有的 tag（分类依次为宏定义、数据结构、变量、函数），并且每类 tag 都按各 tag在文件中出现的先后顺序排序，如图所示："
                    }
                ]
            },
            "bbox": [
                144,
                217,
                848,
                269
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/dce8c4e53bc714f4f55eec82fded2a9e3896d366bcaab3d959e04c36d99c3fba.jpg"
                },
                "image_caption": [],
                "image_footnote": []
            },
            "bbox": [
                152,
                275,
                850,
                357
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/6469cb9dfa4d70014ba7dda7cff09ad369d02f55d440934a939a1305983a020b.jpg"
                },
                "image_caption": [],
                "image_footnote": []
            },
            "bbox": [
                152,
                367,
                850,
                414
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/9f6aa32b5761b70f4ec343fdba29ff0f71876766038e13836425ac5dd421decd.jpg"
                },
                "image_caption": [],
                "image_footnote": []
            },
            "bbox": [
                152,
                425,
                850,
                542
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（2）关闭 taglist 窗口："
                    }
                ]
            },
            "bbox": [
                152,
                571,
                342,
                585
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在vim命令方式下再次运行上述（1）中三个命令之一，则关闭taglist窗口。"
                    }
                ]
            },
            "bbox": [
                144,
                589,
                747,
                604
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（3） 在taglist窗口中常用的快捷键："
                    }
                ]
            },
            "bbox": [
                154,
                608,
                457,
                623
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "1）Ctrl+ww 在taglist窗口和文件编辑窗口之间切换焦点"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "2） "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\langle \\mathrm { C t r } 1 \\rangle + ]"
                            },
                            {
                                "type": "text",
                                "content": "跳转到光标所在 tag 的定义位置；用鼠标双击此 tag 功能相同"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "3）o 在一个新窗口中显示光标所在 tag 的定义位置；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "4）<Space> 显示光标下 tag 的原型定义；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "5）u 更新 taglist 窗口中的 tag"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "6）s 更改排序方式，在按名字排序和按出现顺序排序间切"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "7）x taglist 窗口放大和缩小，方便查看较长的 tag"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "8）[[ 跳到前一个文件"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "9）]] 跳到后一个文件"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "9）q 关闭 taglist 窗口 "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "10）<F1> 显示帮助"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                179,
                627,
                784,
                829
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "6.1.4 安装使用 Cscope"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                843,
                405,
                859
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "通过Cscope可以很方便地找到某个函数或变量的定义位置、被调用的位置等信息。Cscope已经是Vim的标准特性，默认都有支持，官方网址为http://cscope.sourceforge.net/。"
                    }
                ]
            },
            "bbox": [
                144,
                87,
                821,
                142
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1． 安装 Cscope 插件"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                159,
                352,
                175
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在 ubuntu 下安装 Cscope："
                    }
                ]
            },
            "bbox": [
                181,
                196,
                383,
                211
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "直接运行命令：apt-get install cscope"
                    }
                ]
            },
            "bbox": [
                181,
                215,
                505,
                230
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "使用源码安装："
                    }
                ]
            },
            "bbox": [
                181,
                234,
                302,
                248
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "从 http://cscope.sourceforge.net/下载 Cscope 源代码包编译安装，步骤同 Ctags 安装过程。"
                    }
                ]
            },
            "bbox": [
                144,
                253,
                848,
                288
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2． 以 root 身份配置 Cscope 插件"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                305,
                450,
                322
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "1）下载 http://cscope.sourceforge.net/cscope_maps.vim 文件到/etc/vim/plugin目录中；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "2）生成 cscope 数据库文件："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                146,
                342,
                840,
                395
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "进入linux源码根目录，执行下面命令："
                    }
                ]
            },
            "bbox": [
                179,
                399,
                494,
                414
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#cscope -Rbqk "
                    }
                ]
            },
            "bbox": [
                181,
                419,
                312,
                432
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "该命令将生成三个文件：cscope.out, cscope.in.out, cscope.po.out，如图所示："
                    }
                ]
            },
            "bbox": [
                181,
                436,
                828,
                451
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "root@ubuntu:/home/zwh/linux-2.6.24#sccope-Rbkq root@ubuntu:/home/zwh/linux-2.6.24# ls arch cscope.in.out fs kernel net security block cscope.out include lib README sound COPYING cscope.po.out init MAINTAINERS REPORTING-BUGS tags "
                    }
                ],
                "code_language": "batch"
            },
            "bbox": [
                147,
                470,
                853,
                539
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "其中cscope.out 是基本的符号索引，后两个文件是使用\"-q\"选项生成的，可以加快cscope的索引速度。cscope 命令的参数含义如下："
                    }
                ]
            },
            "bbox": [
                144,
                563,
                831,
                596
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-R: 在生成索引文件时，搜索子目录树中的代码"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-b: 只生成索引文件，不进入 cscope的界面"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-d: 只调出 cscope gui 界面，不跟新 cscope.out"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-k: 在生成索引文件时，不搜索/usr/include 目录"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-q: 生成 cscope.in.out 和 cscope.po.out 文件，加快 cscope 的索引速度"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-i: 如果保存文件列表的文件名不是 cscope.files时，需要加此选项告诉 cscope到哪儿去找源文件列表。可以使用\"-\"，表示由标准输入获得文件列表。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                601,
                848,
                728
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-I dir: 在-I选项指出的目录中查找头文件"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-u: 扫描所有文件，重新生成交叉索引文件"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-C: 在搜索时忽略大小写"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-P path: 在以相对路径表示的文件前加上 path，这样，你不用切换到你数据库文件所在的目录也可以使用它了。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                733,
                843,
                824
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3）载入cscope数据库文件"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                827,
                400,
                843
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "使用cscope之前，需将前面生成的数据库文件载入到 vim中。如果之前已经下载过cscope_maps.vim 文件到/etc/vim/plugin 目录下，可忽略这一步。"
                    }
                ]
            },
            "bbox": [
                144,
                846,
                830,
                881
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "注意：生成的 cscope.out 和 tags 文件要在打开 vim 所在的文件夹，否则 vim 无法找到相关符号信息。"
                    }
                ]
            },
            "bbox": [
                144,
                87,
                848,
                121
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "进入 linux 源码根目录，在 vim 中运行以下命令即可："
                    }
                ]
            },
            "bbox": [
                179,
                124,
                601,
                140
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": ": cscope add cscope.out "
                    }
                ]
            },
            "bbox": [
                243,
                145,
                452,
                159
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "到这里，就可以开始使用 Cscope 了。"
                    }
                ]
            },
            "bbox": [
                189,
                162,
                477,
                178
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3． 使用 Cscope 插件"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                196,
                352,
                212
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Cscope 的查看命令都是在 vim 的命令方式下运行的。"
                    }
                ]
            },
            "bbox": [
                179,
                234,
                584,
                248
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "cscope find 命令："
                    }
                ]
            },
            "bbox": [
                181,
                253,
                329,
                268
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在vim中添加cscope数据库文件后，就可以调用\"cscope find\"命令查找源码相关内容，如函数、变量、数据结构的定义及调用情况。vim支持 8种 cscope的查询功能，描述如下："
                    }
                ]
            },
            "bbox": [
                144,
                271,
                845,
                305
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "s: 查找C语言符号，即查找函数名、宏、枚举值等出现的地方"
                    }
                ]
            },
            "bbox": [
                179,
                309,
                673,
                325
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "g: 查找函数、宏、枚举等定义的位置，类似 ctags 所提供的功能"
                    }
                ]
            },
            "bbox": [
                206,
                328,
                715,
                344
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "d: 查找本函数调用的函数"
                    }
                ]
            },
            "bbox": [
                181,
                347,
                389,
                362
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "c: 查找调用本函数的函数"
                    }
                ]
            },
            "bbox": [
                181,
                366,
                389,
                381
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "t: 查找指定的字符串"
                    }
                ]
            },
            "bbox": [
                181,
                385,
                352,
                399
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "e: 查找 egrep 模式，相当于 egrep 功能，但查找速度快多了"
                    }
                ]
            },
            "bbox": [
                179,
                403,
                652,
                419
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "f: 查找并打开文件，类似 vim 的 find 功能"
                    }
                ]
            },
            "bbox": [
                179,
                422,
                522,
                437
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "i: 查找包含本文件的文件"
                    }
                ]
            },
            "bbox": [
                181,
                441,
                389,
                456
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "命令运用举例："
                    }
                ]
            },
            "bbox": [
                181,
                479,
                300,
                494
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "查看函数、宏、枚举等的定义位置："
                    }
                ]
            },
            "bbox": [
                181,
                498,
                457,
                513
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": ":cscope find g 函数（宏、枚举）名 "
                    }
                ]
            },
            "bbox": [
                181,
                517,
                477,
                532
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "或：:cs find g 函数（宏、枚举）名 "
                    }
                ]
            },
            "bbox": [
                179,
                537,
                477,
                551
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如执行：cscope find g effective_prio，将显示该函数的实现源码。"
                    }
                ]
            },
            "bbox": [
                179,
                555,
                722,
                570
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "查看函数、宏、枚举等的调用位置："
                    }
                ]
            },
            "bbox": [
                181,
                574,
                457,
                588
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": ":cscope find c 函数（宏、枚举）名 "
                    }
                ]
            },
            "bbox": [
                181,
                593,
                477,
                607
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "或：:cs find c 函数（宏、枚举）名 "
                    }
                ]
            },
            "bbox": [
                181,
                611,
                477,
                626
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如执行：cscope find c effective_prio，将显示所有调用该函数（宏、枚举）的位置，如图所示："
                    }
                ]
            },
            "bbox": [
                144,
                630,
                836,
                664
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "Cscope tag: effective_priorio\n# line filename / context / line\n1 1761 kernel/sched.c <<wake_up_new_task\np->prio = effective_prio(p);\n2 4098 kernel/sched.c <<set_user_nice>> p->prio = effective_prio(p);\nType number and <Enter> (empty Cancelcs): "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                287,
                684,
                710,
                772
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "其他命令选项的功能请读者自行实践。"
                    }
                ]
            },
            "bbox": [
                181,
                794,
                477,
                809
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3）Cscope 中常用快捷键"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                813,
                376,
                828
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在cscope_maps.vim文件中定义了一组快捷键执行前面的命令，具体使用方法请读者自行上机实践。"
                    }
                ]
            },
            "bbox": [
                144,
                832,
                845,
                865
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4）返回上一次界面："
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                870,
                342,
                884
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "快捷键“ctrl+t”返回上一次界面。"
                    }
                ]
            },
            "bbox": [
                181,
                888,
                458,
                903
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "更多功能可通过命令 man cscope 或在 Vim 命令行下运行 help cscope 查询。"
                    }
                ]
            },
            "bbox": [
                181,
                87,
                766,
                104
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "6.1.5 source insight "
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                126,
                329,
                140
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Source insight是一款 Windows下的面向项目开发的代码编辑浏览器，它可以自动同步分析相关源码，为我们的开发及源码分析提供了很大便利。"
                    }
                ]
            },
            "bbox": [
                144,
                161,
                843,
                195
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1.安装 source insight 软件"
                    }
                ],
                "level": 1
            },
            "bbox": [
                146,
                212,
                374,
                229
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "到网上搜索该软件，可以安装一个 30天免费的版本，如图所示："
                    }
                ]
            },
            "bbox": [
                181,
                250,
                678,
                266
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "Source Insight 软件下载 一键安装 360软件宝库"
                    }
                ],
                "level": 1
            },
            "bbox": [
                154,
                288,
                500,
                303
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/b966210afb24171ff27802ac0d7dcccb8dfacae1774a68c30c774d44891a0078.jpg"
                },
                "image_caption": [],
                "image_footnote": []
            },
            "bbox": [
                154,
                305,
                694,
                411
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "当然，也可以在 linux下通过wine 安装 source insight，安装过程可以参考如下资源：http://blog.csdn.net/gaojinshan/article/details/9272123"
                    }
                ]
            },
            "bbox": [
                186,
                430,
                831,
                464
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "注意：wine 安装在当前用户目录下，且是隐藏的，用ls -a可见，也可通过图形界面直接看。安装好的 sourceinsight 程序放在 wine/driver_c/Program Files(x86)/下。可直接通过点击启动。"
                    }
                ]
            },
            "bbox": [
                157,
                467,
                848,
                521
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. 新建工程"
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                577,
                250,
                592
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "1）运行 source insight"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "2）选择 project->New project 新建一个工程，如图所示："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                181,
                614,
                633,
                648
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/4fd6a303cac45caa797714b44e86cae16f19946ef87fc8968666f3d8f52db573.jpg"
                },
                "image_caption": [],
                "image_footnote": []
            },
            "bbox": [
                152,
                663,
                747,
                777
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "输入新建工程的名字及工程文件的保存路径，单击“OK”关闭该窗口，将同时打开新建工程的设置对话框，如图所示："
                    }
                ]
            },
            "bbox": [
                144,
                796,
                850,
                831
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/76fec6db73191d2cb4ff810c24067cf91a461e94816244d23d52715c95a68c81.jpg"
                },
                "image_caption": [],
                "image_footnote": []
            },
            "bbox": [
                152,
                89,
                853,
                506
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "3）在上面的设置对话框中，首先设置配置文件，可采用默认设置，也可以选择“Projecthas its own configuration file”；然后选择要添加代码的目录，如本示例设置为 linux源码所在目录："
                    }
                ]
            },
            "bbox": [
                144,
                530,
                848,
                583
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/70169cfda03b9cc821a7d21997c442a2997def5df6ac33c7be44da8ac9e6c2f0.jpg"
                },
                "image_caption": [],
                "image_footnote": []
            },
            "bbox": [
                157,
                606,
                872,
                652
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "最后单击“OK”关闭该对话框，将打开工程文件加载对话框，如图所示："
                    }
                ]
            },
            "bbox": [
                181,
                675,
                739,
                690
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/c393fc5f81f73ab21b845c4e4e345edd9e2f13053e4ed783f4867dbd07e55776.jpg"
                },
                "image_caption": [],
                "image_footnote": []
            },
            "bbox": [
                152,
                92,
                852,
                356
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "可直接选择刚才的 linux源码目录，单击“Add Tree”按钮，将递归加入指定目录中所有文件到工程中。关闭该对话框。"
                    }
                ]
            },
            "bbox": [
                144,
                365,
                848,
                399
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4）“同步”文件或者“重编译”工程"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                403,
                478,
                417
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "这是很重要的一步，将对代码间调用关系等进行内部初始化。推荐大家进行“重新编译”工程，这样可以建立一个与路径无关的工程，也就是这个工程拿到哪都可以使用，而同步不可以。操作方法是："
                    }
                ]
            },
            "bbox": [
                144,
                420,
                848,
                475
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "同步文件：选择 project->synchronize file…，在显示的对话框中你可以选择：Removemissing files from projcet 和 Suppress warning messages,或者再加上 Force all filesto be re-parsed，然后单击“OK”，之后工程中的源码就可以进行关联了。"
                    }
                ]
            },
            "bbox": [
                144,
                479,
                850,
                532
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "重编译工程：选择 project->rebuild project… ，在显示的对话框中，只选择第三项：Re-Create the whole project from scratch,然后单击“OK”就可以了。"
                    }
                ]
            },
            "bbox": [
                144,
                535,
                840,
                570
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3.使用 sought insight 查看源码"
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                588,
                408,
                604
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "启动 soughtinsight，选择 project->Open Project…打开工程，如前面建立的 test工程，默认是打开三个窗口，如图所示："
                    }
                ]
            },
            "bbox": [
                144,
                90,
                833,
                124
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/42513e383a540bb5e6386f3178deb44d628f914b827c28b5f933adcf355969f2.jpg"
                },
                "image_caption": [],
                "image_footnote": []
            },
            "bbox": [
                149,
                130,
                853,
                381
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（1）查看函数及变量："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                405,
                359,
                420
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在“工程窗口”中选择并双击一个要查看的文件，将在“文件窗口”显示该文件的所有内容：包含的头文件、定义的变量、函数（包括函数中的变量定义、所调用的其他函数等），在其中选择一个函数（或变量）并单击，将在“内容窗口”中显示该函数（或变量）的详细定义，如图所示："
                    }
                ]
            },
            "bbox": [
                144,
                424,
                848,
                495
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/fb4b40848430dc9246725c30e9d9e4a5c647bc258b41a1faf38ec74a3418c551.jpg"
                },
                "image_caption": [],
                "image_footnote": []
            },
            "bbox": [
                149,
                519,
                853,
                728
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "此时如果再单击工具栏上的“relation window”，将显示所有调用该函数的位置，如图中右下角窗口所示："
                    }
                ]
            },
            "bbox": [
                144,
                756,
                847,
                790
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/521fa64fb51d96ca6e8768cc65be06fae4fb3793b285609fbe993befd385f756.jpg"
                },
                "image_caption": [],
                "image_footnote": []
            },
            "bbox": [
                149,
                87,
                855,
                360
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（2）搜索字符串"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                382,
                319,
                397
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "单击工具栏上的“R”按钮，将显示字符串查找窗口“Lookup References”，其中查找选项“Options”按如图设置即可，如图所示："
                    }
                ]
            },
            "bbox": [
                144,
                400,
                848,
                435
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（3）使用鼠标右键功能"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                439,
                374,
                454
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在source insight中，对任何文件、函数或者变量点击鼠标右键，会显示一个快捷菜单，能更加方便的实现跳转功能，请大家参考其他相关资料学习。"
                    }
                ]
            },
            "bbox": [
                144,
                457,
                848,
                492
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/944d196d99288cc023949a198d0b741ab2b900b3642b9ea4fab3e55e37f8da63.jpg"
                },
                "image_caption": [],
                "image_footnote": []
            },
            "bbox": [
                147,
                497,
                771,
                766
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如查找“effective_prio”,单击“Search”后显示结果如图所示："
                    }
                ]
            },
            "bbox": [
                181,
                772,
                697,
                789
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/bc6e2c47242f2e9fca0219e263bef1d2411166f22d5e435e0f14c52b3a5e8680.jpg"
                },
                "image_caption": [],
                "image_footnote": []
            },
            "bbox": [
                147,
                86,
                853,
                214
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "点击左边或工具栏中的红色小按钮就可以展开内容，其中工具栏中的按钮下面还有一个红色的“向左箭头”和“向右箭头”，标明一个向前，一个向后依次打开，非常方便。"
                    }
                ]
            },
            "bbox": [
                144,
                233,
                848,
                268
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "6.2 linux 中的汇编语言"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                294,
                452,
                313
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "虽然Linux内核的绝大部分代码是用 C 语言编写的，但仍然不可避免地在某些关键地方使用了汇编代码，其中主要是在 Linux 的启动部分。Linux主要使用AT&T汇编语言，它与intel汇编大同小异，为方便大家阅读源码，下面简单介绍 AT&T汇编的一些基本知识。"
                    }
                ]
            },
            "bbox": [
                144,
                341,
                848,
                395
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "6.2.1 AT&T 与 intel 汇编的语法格式比较"
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                417,
                475,
                432
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. 寄存器及立即数的前缀 "
                    }
                ],
                "level": 1
            },
            "bbox": [
                176,
                454,
                389,
                469
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在 AT&T 汇编格式中，寄存器名前要冠以 “%”，立即数前要冠以“$”；而在 Intel 汇编格式中，寄存器名及立即数都不需要加前缀。例如："
                    }
                ]
            },
            "bbox": [
                144,
                489,
                848,
                524
            ]
        },
        {
            "type": "table",
            "content": {
                "image_source": {
                    "path": "images/dea4555304cbce1723f54c3c6fb58b97f6419d4640b30a694c9dd9edd2a82838.jpg"
                },
                "table_caption": [],
                "table_footnote": [],
                "html": "<table><tr><td>AT&amp;T 格式</td><td>Intel 格式</td></tr><tr><td>pushl %eax</td><td>push eax</td></tr><tr><td>pushl $1</td><td>push 1</td></tr></table>",
                "table_type": "simple_table",
                "table_nest_level": 1
            },
            "bbox": [
                205,
                525,
                712,
                606
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. 操作数的方向"
                    }
                ],
                "level": 1
            },
            "bbox": [
                176,
                627,
                317,
                643
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "AT&T 和 Intel 格式中的源操作数和目标操作数的位置正好相反。在 Intel 汇编格式中，目标操作数在源操作数的左边；而在 AT&T 汇编格式中，目标操作数在源操作数的右边。例如："
                    }
                ]
            },
            "bbox": [
                144,
                663,
                848,
                714
            ]
        },
        {
            "type": "table",
            "content": {
                "image_source": {
                    "path": "images/d34f4a1407f7e75fadb3952c3810975428d129585c23c4d7a291b48c57124364.jpg"
                },
                "table_caption": [],
                "table_footnote": [],
                "html": "<table><tr><td>AT&amp;T 格式</td><td>Intel 格式</td></tr><tr><td>add1 $1, %eax</td><td>add eax, 1</td></tr></table>",
                "table_type": "simple_table",
                "table_nest_level": 1
            },
            "bbox": [
                203,
                717,
                712,
                771
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3. 操作数的字长"
                    }
                ],
                "level": 1
            },
            "bbox": [
                176,
                791,
                319,
                808
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在 AT&T 汇编格式中，操作数的字长由操作符的最后一个字母决定，后缀'b'、'w'、'l分别表示操作数为字节（byte，8 比特）、字（word，16 比特）和长字（long，32 比特）；而在 Intel 汇编格式中，操作数的字长是用 \"byte ptr\" 和 \"word ptr\" 等前缀来表示的。例如："
                    }
                ]
            },
            "bbox": [
                144,
                828,
                843,
                898
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "table",
            "content": {
                "image_source": {
                    "path": "images/1f4bb0efe3b9d9fc24f6bdb32f596e5d6c8697dfa185231ee792620a94782180.jpg"
                },
                "table_caption": [],
                "table_footnote": [],
                "html": "<table><tr><td>AT&amp;T 格式</td><td>Intel 格式</td></tr><tr><td>movb val, %a1</td><td>mov al, byte ptr val</td></tr></table>",
                "table_type": "simple_table",
                "table_nest_level": 1
            },
            "bbox": [
                203,
                84,
                712,
                140
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4. Jump 和 call 指令的前缀"
                    }
                ],
                "level": 1
            },
            "bbox": [
                176,
                160,
                403,
                177
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在 AT&T 汇编格式中，绝对转移和调用指令（jump/call）的操作数前要加上'*'作为前缀，而在 Intel 格式中则不需要。"
                    }
                ]
            },
            "bbox": [
                144,
                195,
                847,
                231
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5. 内存单元操作数"
                    }
                ],
                "level": 1
            },
            "bbox": [
                176,
                252,
                337,
                269
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "内存单元操作数的寻址方式是间接寻址。在 AT&T 汇编格式中，基址寄存器用（）括起来，而Intel中用[]括起来。例如："
                    }
                ]
            },
            "bbox": [
                144,
                288,
                848,
                321
            ]
        },
        {
            "type": "table",
            "content": {
                "image_source": {
                    "path": "images/9bbd2ad3da6ffe9a463e5a1b789c89043941b21c83e8976dfc904f8e0fceb0e1.jpg"
                },
                "table_caption": [],
                "table_footnote": [],
                "html": "<table><tr><td>AT&amp;T 格式</td><td>Intel 格式</td></tr><tr><td>movl -4(%ebp), %eax</td><td>mov eax, [ebp - 4]</td></tr><tr><td>movl 5(%ebx),%eax</td><td>mov eax, [ebx+5]</td></tr></table>",
                "table_type": "simple_table",
                "table_nest_level": 1
            },
            "bbox": [
                203,
                323,
                712,
                405
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "6.2.2 Gcc 嵌入式汇编 "
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                425,
                324,
                441
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux 下用汇编语言编写的代码具有两种不同的形式。第一种是整个程序全部用汇编语言编写；第二种是内嵌的汇编代码，指嵌入到C 语言程序中的汇编代码片段。下面介绍gcc嵌入式汇编的相关知识。"
                    }
                ]
            },
            "bbox": [
                144,
                460,
                848,
                514
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. 嵌入式汇编的一般形式"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                536,
                394,
                551
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "asm __volatile__(\"asm statements\" //指令部"
                    }
                ]
            },
            "bbox": [
                181,
                571,
                618,
                587
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": ": outputs （optional） //输出部"
                    }
                ]
            },
            "bbox": [
                184,
                590,
                468,
                606
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": ": inputs （optional） //输入部"
                    }
                ]
            },
            "bbox": [
                184,
                609,
                460,
                625
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": ": modified （optional） //修改部"
                    }
                ]
            },
            "bbox": [
                184,
                629,
                468,
                643
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": []
            },
            "bbox": [
                183,
                648,
                201,
                661
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "下面对语句格式的各部分分别进行说明："
                    }
                ]
            },
            "bbox": [
                181,
                665,
                492,
                681
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1）__asm_"
                    }
                ]
            },
            "bbox": [
                189,
                686,
                292,
                700
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "表示汇编代码的开始，也可以写成“asm”，两者完全相同。"
                    }
                ]
            },
            "bbox": [
                181,
                703,
                643,
                719
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（2）__volatile__"
                    }
                ]
            },
            "bbox": [
                189,
                722,
                337,
                738
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "这是一个可选项，它告诉编译器不要优化该汇编语句，主要用于硬件级程序设计。"
                    }
                ]
            },
            "bbox": [
                179,
                741,
                811,
                756
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（3）指令部：\"asm statements\""
                    }
                ]
            },
            "bbox": [
                189,
                760,
                442,
                775
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "是汇编指令部分，可以是一条或多条指令。如果是多条指令，则指令间需要使用“\\n\\t”进行分隔。"
                    }
                ]
            },
            "bbox": [
                144,
                778,
                840,
                813
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如读 CR0 寄存器的 read_cr0()的定义为："
                    }
                ]
            },
            "bbox": [
                181,
                816,
                497,
                833
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "static inline unsigned long read_cr0(void) "
                    }
                ]
            },
            "bbox": [
                181,
                835,
                554,
                851
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "{ "
                    }
                ]
            },
            "bbox": [
                184,
                854,
                200,
                869
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "unsigned long cr0; //汇编内部定义的局部变量"
                    }
                ]
            },
            "bbox": [
                233,
                873,
                628,
                889
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "asm volatile(\"movq %%cr0, "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\% 0 ^ { \\prime \\prime }"
                    },
                    {
                        "type": "text",
                        "content": ": "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\prime \\prime = \\mathrm { r } ^ { \\prime \\prime }"
                    },
                    {
                        "type": "text",
                        "content": "(cr0)); // 嵌入式汇编语句 "
                    }
                ]
            },
            "bbox": [
                233,
                892,
                786,
                909
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                63
            ]
        }
    ],
    [
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "return cr0; "
                    }
                ],
                "code_language": "lua"
            },
            "bbox": [
                181,
                87,
                334,
                121
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "使用嵌入式汇编时，汇编语句中的操作数如何与 C 代码中的变量相结合是个很大的问题。GCC的解决方法是：需要使用指定寄存器的值时，寄存器名前面应该加上两个'%'，如示例中的“%%cr0”表示使用 "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\mathrm { c r 0 }"
                    },
                    {
                        "type": "text",
                        "content": "寄存器；需要使用C代码中的变量时，采用加上前缀“%”的数字(如%0，%1)来表示，其中数字是从输出部的第一个约束开始从 0依次编号。如示例汇编语句中的操作数“%0”对应输出部的“cr0”变量。"
                    }
                ]
            },
            "bbox": [
                144,
                124,
                858,
                218
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（4）输出部：: outputs （optional）"
                    }
                ]
            },
            "bbox": [
                189,
                237,
                487,
                254
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "输出部分用于规定输出变量（目标操作数）如何与汇编语句中的操作数相结合的约束条件，可以有多个约束，以逗号分开。每个约束以“ "
                    },
                    {
                        "type": "equation_inline",
                        "content": "= ^ { \\mathfrak { p } }"
                    },
                    {
                        "type": "text",
                        "content": "开头（表示只用输出），接着用一个字母来表示操作数的类型，最后用“（）”说明变量名。"
                    }
                ]
            },
            "bbox": [
                144,
                256,
                850,
                311
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如上例中的："
                    }
                ]
            },
            "bbox": [
                181,
                313,
                282,
                329
            ]
        },
        {
            "type": "algorithm",
            "content": {
                "algorithm_caption": [],
                "algorithm_content": [
                    {
                        "type": "text",
                        "content": "：  "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\mathbf{\\Pi}^{\\prime \\prime} = \\mathbf{r}^{\\prime \\prime}"
                    },
                    {
                        "type": "text",
                        "content": " (cr0)"
                    }
                ]
            },
            "bbox": [
                218,
                332,
                324,
                348
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "“ "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\mathit { \\Omega } ^ { \\prime } = \\mathrm { { r } } ^ { \\prime \\prime }"
                    },
                    {
                        "type": "text",
                        "content": "表示相应的目标操作数（指令部分的“%0”）可以使用任何一个通用寄存器；并且变量 "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\mathrm { c r 0 }"
                    },
                    {
                        "type": "text",
                        "content": "存放在这个寄存器中。"
                    }
                ]
            },
            "bbox": [
                144,
                351,
                840,
                386
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "实际上，除“=”外，还有其他保留字，相关含义是："
                    }
                ]
            },
            "bbox": [
                181,
                388,
                589,
                405
            ]
        },
        {
            "type": "table",
            "content": {
                "image_source": {
                    "path": "images/e33a4d7802d2fb176ad08d6c1657f7ab7a09e0d6d4f2bab3d0be4fad18ef3d14.jpg"
                },
                "table_caption": [],
                "table_footnote": [],
                "html": "<table><tr><td>保留字</td><td>含义</td></tr><tr><td>=</td><td>只写/输出变量</td></tr><tr><td>+</td><td>可读可写变量</td></tr><tr><td>&amp;</td><td>该输出操作数不能使用输入操作数相同的寄存器</td></tr></table>",
                "table_type": "simple_table",
                "table_nest_level": 1
            },
            "bbox": [
                230,
                405,
                784,
                486
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "下表中列举了x86 中最常用的约束字母及含义："
                    }
                ]
            },
            "bbox": [
                181,
                506,
                544,
                521
            ]
        },
        {
            "type": "table",
            "content": {
                "image_source": {
                    "path": "images/4fe52aecfae56fa250b6cccc25919b7ee34765984b0626b6a0612cf285479a5a.jpg"
                },
                "table_caption": [],
                "table_footnote": [],
                "html": "<table><tr><td>约束字母</td><td>含义</td></tr><tr><td>m, v, o</td><td>表示内存单元</td></tr><tr><td>r</td><td>任意通用寄存器</td></tr><tr><td>q</td><td>寄存器EAX/EBX/ECX/EDX之一</td></tr><tr><td>a, b, c, d</td><td>表示寄存器EAX/EBX/ECX/EDX</td></tr><tr><td>S, D</td><td>寄存器ESI或EDI</td></tr><tr><td>A</td><td>与a+b相同，使用EAX与EBX联合，形成一个64位寄存器</td></tr><tr><td>I</td><td>常数0-31</td></tr></table>",
                "table_type": "simple_table",
                "table_nest_level": 1
            },
            "bbox": [
                183,
                521,
                784,
                680
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（5）输入部：: inputs （optional）"
                    }
                ]
            },
            "bbox": [
                189,
                700,
                477,
                715
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "输入约束格式与输出约束相似，但是没有“=”号。如果一个输入约束要求使用寄存器，则GCC在预处理时就会为之分配一个寄存器，并插入必要的指令将操作数装入该寄存器。如果输入部某个操作数所要求使用的寄存器与前面输出部某个操作数所要求的是同一个寄存器，就把输出部对应操作数的编号（如“0”、“1”等）放在输入部中相应位置，但在输入部中的参数编号需要另外从新编号。程序样例见后面“linux源码中嵌入式汇编举例”中的switch_to()函数。"
                    }
                ]
            },
            "bbox": [
                144,
                719,
                848,
                828
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（6）修改部：: registers_modified （optional）"
                    }
                ]
            },
            "bbox": [
                189,
                832,
                584,
                848
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "汇编语句在执行过程中可能会修改某些寄存器或者内存单元的值，在这里进行列出。一般是\"memory\",表示内存发现变化：:\"memory\""
                    }
                ]
            },
            "bbox": [
                144,
                848,
                850,
                883
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "此外还有 cc,表示改变条件代码寄存器(condition code register),或者某个寄存器名字等。"
                    }
                ]
            },
            "bbox": [
                144,
                85,
                843,
                118
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "需要说明的是，上述各部分中，指令部是必须的，输入部、输出部及修改部是可选的，当输入部存在，而输出部不存在时，冒号“:”要保留；当修改部存在时，三个冒号都要保留。如宏定义__cli()："
                    }
                ]
            },
            "bbox": [
                144,
                124,
                848,
                177
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "define __cli() __asm__ __volatile__( \"cli\": : : \"memory\") "
                    }
                ],
                "code_language": "yaml"
            },
            "bbox": [
                179,
                181,
                721,
                197
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "下面是一个简单的嵌入式汇编程序，其功能是将变量 a 的值赋予变量 b，请大家自行分析："
                    }
                ]
            },
            "bbox": [
                144,
                199,
                848,
                233
            ]
        },
        {
            "type": "algorithm",
            "content": {
                "algorithm_caption": [],
                "algorithm_content": [
                    {
                        "type": "text",
                        "content": "/\\*Embedded.c\\*/   \nint main()   \n{ int  "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\mathrm{a} = 10"
                    },
                    {
                        "type": "text",
                        "content": " ，  "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\mathrm{b} = 0"
                    },
                    {
                        "type": "text",
                        "content": " ： _asm_ volatile_(\"movl %1,%%eax;\\\\n\\\\r\" \"movl%%eax，  "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\% 0"
                    },
                    {
                        "type": "text",
                        "content": " ：  "
                    },
                    {
                        "type": "equation_inline",
                        "content": "^{\\prime \\prime} = \\mathrm{r}^{\\prime \\prime}(\\mathrm{b})"
                    },
                    {
                        "type": "text",
                        "content": " /\\*输出部\\*/ :\"\\r\"(a) /\\*输入部\\*/ :\"\\%eax\"); /\\*修改部\\*/ printf(\"Result:%d,%d\\\\n\",a,b);   \n}"
                    }
                ]
            },
            "bbox": [
                179,
                237,
                638,
                442
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. Linux 源码中嵌入式汇编举例"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                463,
                442,
                479
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1）简单应用："
                    }
                ]
            },
            "bbox": [
                189,
                499,
                307,
                514
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "define __save_flags(x) \\  \nasm volatile (\"stc ccr, %w0\": \"=r\" (x)) //将 flags 值压栈  \n#define __restore_flags(x) \\  \nasm volatile (\"ldc %w0, ccr\": \"r\" (x)) //恢复 flags 值到 cpu 中 "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                181,
                518,
                794,
                590
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（2）复杂应用："
                    }
                ]
            },
            "bbox": [
                189,
                594,
                307,
                609
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "static inline int strcmp(const char *cs, const char *ct)  \n{  \n    char res;  \n    asm(\"\\n\")  \n    \"1: move.b (%0)+,%2\\n\" /* get *cs */  \n    \" cmp.b (%1)+,%2\\n\" /* compare a byte */  \n    \" jne 2f\\n\" /* not equal, break out */  \n    \" tst.b %2\\n\" /* at end of cs? */  \n    \" jne 1b\\n\" /* no, keep going */  \n    \" jra 3f\\n\" /* strings are equal */  \n    \"2: sub.b -(%1),%2\\n\" /* *cs - *ct */  \n    \"3:\"  \n        : \"+\" (cs), \"+\" (ct), \"=\" (res));  \n    return res; "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                181,
                612,
                840,
                894
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "第二个例子是函数 switch_to()（include/asm-x86/system_32.h 文件中），它是 linux上下文切换的核心部分："
                    }
                ]
            },
            "bbox": [
                144,
                87,
                848,
                121
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "1 extern struct task_struct *FASTCALL(_switch_to(struct task_struct *prev, struct task_struct *next));  \n2 #define switch_to(prev, next, last) do {  \n3 unsigned long esi,EDI;  \n4 asm volatile(\"pushfl\\n\\t\" /* Save flags */  \n5 \"pushl%%ebp\\n\\t\"  \n6 \"mov1%%esp,%0\\n\\t\" /* save ESP */  \n7 \"mov1%5,%%esp\\n\\t\" /* restore ESP */  \n8 \"mov1$1f,%1\\n\\t\" /* save EIP */  \n9 \"push1%6\\n\\t\" /* restore EIP */  \n10 \"jmp __switch_to\\n\"  \n11 \"1:\\t\"  \n12 \"pop1%%ebp\\n\\t\"  \n13 \"popfl\"  \n14 :=\"m\" (prev->thread.asp), \"=\"m\" (prev->thread.eip),  \n15 :=a\" (last),\"=S\" (esi), \"=\"D\" (edi)  \n16 : \"m\" (next->thread.asp), \"m\" (next->thread.eip),  \n17 \"2\" (prev), \"d\" (next));  \n18 } while (0) "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                181,
                124,
                848,
                480
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "下面对上述代码做简单介绍："
                    }
                ]
            },
            "bbox": [
                181,
                483,
                403,
                499
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "第 1 行：FASTCALL 告诉编译程序使用 register 传递参数，而“asmlinkage”标记则要求采用stack传递参数；"
                    }
                ]
            },
            "bbox": [
                144,
                502,
                848,
                536
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "第11行：参数1 被用作返回地址；"
                    }
                ]
            },
            "bbox": [
                181,
                541,
                448,
                555
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "第 14-15 行：输出参数部分，各参数 prev->thread.esp、prev->thread.eip、last、esi、edi 对应的编号分别是： "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\% 0"
                    },
                    {
                        "type": "text",
                        "content": "、%1、 "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\% 2"
                    },
                    {
                        "type": "text",
                        "content": "、%3、%4；"
                    }
                ]
            },
            "bbox": [
                144,
                560,
                833,
                593
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "第 16-17 行：输入参数部分，各参数 next->thread.esp、next->thread.eip、prev、next对应的编号分别是： "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\% 5"
                    },
                    {
                        "type": "text",
                        "content": "、%6、%7、 "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\% 8"
                    },
                    {
                        "type": "text",
                        "content": "，其中 34行上的参数prev与输出部中的 2号参数使用同一寄存器eax，所以在约束位置填写“2”。"
                    }
                ]
            },
            "bbox": [
                144,
                596,
                842,
                650
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "6.3 特殊的C 语言用法"
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                690,
                329,
                707
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1.asmlinkage 及 FASTCALL "
                    }
                ],
                "level": 1
            },
            "bbox": [
                146,
                728,
                356,
                744
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "asmlinkage告诉编译程序使用堆栈传递参数，而FASTCALL通知编译程序使用通用寄存器传递参数。"
                    }
                ]
            },
            "bbox": [
                144,
                764,
                848,
                799
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如获取系统时间函数："
                    }
                ]
            },
            "bbox": [
                181,
                803,
                351,
                816
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "asmlinkage long sys_gettimeofday(struct timeval __user *tv, structtimezone __user *tz) "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                179,
                822,
                747,
                854
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "实现上下文切换函数："
                    }
                ]
            },
            "bbox": [
                181,
                860,
                352,
                873
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "struct task_struct FASTCALL * __switch_to(struct task_struct *prev_p, struct task_struct *next_p) "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                161,
                879,
                843,
                913
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. UL "
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                90,
                196,
                104
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "UL 常被用在数值常数后，标明该常数是“unsigned long”类型，以保证特定体系结构内的数据不会溢出其数据类型所规定的范围。如："
                    }
                ]
            },
            "bbox": [
                144,
                124,
                847,
                159
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */ "
                    }
                ]
            },
            "bbox": [
                179,
                162,
                847,
                178
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3. static inline "
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                200,
                294,
                215
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "被关键字static inline修饰的函数建议gcc在编译时将其代码插入到所有调用它的程序中，从而节省了函数调用的开销。但使用inline会增加二进制映像的大学，可能会降低访问CPU高速缓存的速度。"
                    }
                ]
            },
            "bbox": [
                144,
                236,
                847,
                288
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4.const 和 volatile"
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                312,
                310,
                326
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "const不一定只代表常数，有时也表示“只读”的意思。如“const int *x”中，x是一个指向 const 整数的指针，可以修改该指针，但不能修改这个整数；而在“int const *x”中，x是一个指向整数的const指针，可以修改该整数，但不能修改指针x。"
                    }
                ]
            },
            "bbox": [
                144,
                347,
                847,
                400
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "关键字volatile 通知编译程序每次使用被它修饰的变量时都要重新加载其值，而不是存储并访问一个副本。"
                    }
                ]
            },
            "bbox": [
                144,
                403,
                847,
                437
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5.宏__init "
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                460,
                238,
                475
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "宏__init告诉编译程序相关的函数和变量仅用于初始化。编译程序将标有__init的所有代码存储到特殊的内存段中，初始化结束后就释放这段内存。如编写模块代码的初始化函数时，可以这样定义："
                    }
                ]
            },
            "bbox": [
                144,
                495,
                847,
                548
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "static int __init mymodule_init(void)"
                    }
                ]
            },
            "bbox": [
                181,
                555,
                510,
                570
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "与之类似，如果某些数据也只在初始化时才用到，则可将其标记为__initdata。如ESP设备驱动程序中："
                    }
                ]
            },
            "bbox": [
                144,
                573,
                847,
                606
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "drivers/char/esp.c "
                    }
                ]
            },
            "bbox": [
                189,
                612,
                354,
                626
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "109 static char serial_name[] __initdata "
                    },
                    {
                        "type": "equation_inline",
                        "content": "="
                    },
                    {
                        "type": "text",
                        "content": "\"ESP serial driver\"; "
                    }
                ]
            },
            "bbox": [
                189,
                630,
                757,
                645
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "110 static char serial_version[] __initdata "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\it { \\Delta } = \\it { \\Delta } ^ { \\prime \\prime } 2 . \\it { \\Delta } 2 ^ { \\prime \\prime }"
                    }
                ]
            },
            "bbox": [
                189,
                649,
                660,
                663
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "同样，宏__exit和__exitdata仅用于退出和关闭例程，一般在注销设备驱动程序或模块时才使用。"
                    }
                ]
            },
            "bbox": [
                144,
                667,
                847,
                702
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "6.宏 likely（）和 unlikely（）"
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                724,
                400,
                739
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "现代CPU具有精确的启发式分之预测法，她尝试预测下一条到来的命令，以便达到最高的速度。宏likely 和unlikely允许开发者通过编译程序告诉CPU：某段代码很可能被执行，因而应该预测到；某段代码很可能不被执行，因此不必预测。两个宏的定义如下："
                    }
                ]
            },
            "bbox": [
                144,
                762,
                847,
                819
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "include/linux/compiler.h "
                    }
                ]
            },
            "bbox": [
                181,
                825,
                398,
                840
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "# define likely(x) __builtin_expect(!!(x), 1) "
                    }
                ]
            },
            "bbox": [
                179,
                846,
                589,
                860
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "# define unlikely(x) __builtin_expect(!!(x), 0) "
                    }
                ]
            },
            "bbox": [
                179,
                866,
                623,
                882
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "7．宏 IS_ERR()和 PTR_ERR()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                89,
                371,
                105
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "这两个宏定义在 include/linux/err.h 中。宏 IS_ ERR 用于判断内核函数的返回值是否是一个有效指针，即可用来判断内核代码执行是否有错误；而宏PTR_ERR则返回该错误代码。"
                    }
                ]
            },
            "bbox": [
                144,
                124,
                848,
                160
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "参考文献："
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                181,
                230,
                197
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "1. 陈莉君，康华.linux操作系统原理与应用.北京：清华大学出版社，2012."
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "2. [美]Claudia Salzberg Rodriguzez,Gordon Fischer,Steven Smolski.linux 内核编程.北京：机械工业出版社，2006."
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                179,
                219,
                845,
                275
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "实验一 linux 内核编译及添加系统调用"
                    }
                ],
                "level": 1
            },
            "bbox": [
                233,
                354,
                776,
                379
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1．1 设计目的和内容要求"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                410,
                470,
                429
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1．设计目的"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                464,
                309,
                480
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux是开源操作系统，用户可以根据自身系统需要裁剪、修改内核，定制出功能更加合适、运行效率更高的系统，因此，编译linux内核是进行内核开发的必要基本功。"
                    }
                ]
            },
            "bbox": [
                144,
                497,
                847,
                533
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在系统中根据需要添加新的系统调用是修改内核的一种常用手段，通过本次实验，读者应理解linux系统处理系统调用的流程以及增加系统调用的方法。"
                    }
                ]
            },
            "bbox": [
                144,
                539,
                840,
                576
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2．内容要求"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                588,
                309,
                602
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1）添加一个系统调用，实现对指定进程的 nice 值的修改或读取功能，并返回进程最新的nice 值及优先级 prio。建议调用原型为："
                    }
                ]
            },
            "bbox": [
                144,
                620,
                847,
                656
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "int mysetnice(pid_t pid, int flag, int nicevalue, void __user * prio, void __user * nice); "
                    }
                ]
            },
            "bbox": [
                179,
                664,
                794,
                678
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "参数含义："
                    }
                ]
            },
            "bbox": [
                181,
                684,
                263,
                699
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "pid：进程 ID。"
                    }
                ]
            },
            "bbox": [
                215,
                706,
                324,
                721
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "flag：若值为 0，表示读取 nice 值；若值为 1，表示修改 nice 值。"
                    }
                ]
            },
            "bbox": [
                213,
                727,
                710,
                741
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Prio、nice：进程当前优先级及 nice 值。"
                    }
                ]
            },
            "bbox": [
                215,
                749,
                519,
                763
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "返回值：系统调用成功时返回 0，失败时返回错误码 EFAULT。"
                    }
                ]
            },
            "bbox": [
                181,
                769,
                653,
                784
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）写一个简单的应用程序测试（1）中添加的系统调用。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）若程序中调用了 linux的内核函数，要求深入阅读相关函数源码。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                188,
                791,
                722,
                827
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3. 学时安排（共 4学时）"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                838,
                420,
                854
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4． 开发平台"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                875,
                317,
                891
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux 环境，gcc，gdb，vim 或 gedit 等。"
                    }
                ]
            },
            "bbox": [
                231,
                90,
                537,
                105
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1．2 Linux 系统调用基本概念"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                131,
                500,
                149
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "系统调用的实质是调用内核函数，于内核态中运行。Linux系统中用户（或封装例程）通过执行一条访管指令“int "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\$ 0 x80"
                    },
                    {
                        "type": "text",
                        "content": "来调用系统调用，该指令会产生一个访管中断，从而让系统暂停当前进程的执行，而转去执行系统调用处理程序，通过用户态传入的系统调用号从系统调用表中找到相应服务例程的入口并执行，完成后返回。下面介绍相关的基本概念。"
                    }
                ]
            },
            "bbox": [
                144,
                181,
                848,
                262
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1.系统调用号与系统调用表"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                272,
                440,
                288
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux系统提供了多达几百种的系统调用，为了唯一的标识每一个系统调用，linux为每个系统调用都设置了一个唯一的编号，称为系统调用号；同时每个系统调用需要一个服务例程完成其具体功能。Linux内核中设置了一张系统调用表，用于关联系统调用号及其相对应的服务例程入口地址，定义在./arch/x86/entry/syscalls/syscall_64.tbl 文件中（32 位系统是syscall_32.tbl），每个系统调用占一表项，比如大家比较熟悉的几个系统调用的调用号是："
                    }
                ]
            },
            "bbox": [
                144,
                304,
                848,
                407
            ]
        },
        {
            "type": "table",
            "content": {
                "image_source": {
                    "path": "images/af49f661a62dff2aa564d40553e70dd37b423f3c57754d97bb72faccea67a007.jpg"
                },
                "table_caption": [
                    {
                        "type": "text",
                        "content": "表 7-5 系统调用号举例"
                    }
                ],
                "table_footnote": [],
                "html": "<table><tr><td>系统调用号</td><td>32 位/64 位/common</td><td>系统调用名称</td><td>服务例程入口</td></tr><tr><td>0</td><td>common</td><td>read</td><td>sys_read</td></tr><tr><td>1</td><td>common</td><td>write</td><td>sys_write</td></tr><tr><td>2</td><td>common</td><td>open</td><td>sys_open</td></tr><tr><td>3</td><td>common</td><td>close</td><td>sys_close</td></tr><tr><td>57</td><td>common</td><td>fork</td><td>stub_fork</td></tr></table>",
                "table_type": "simple_table",
                "table_nest_level": 1
            },
            "bbox": [
                171,
                426,
                702,
                638
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "系统调用号非常关键，一旦分配就不能再有任何变更，否则之前编译好的应用程序就会崩溃。在x86中，系统调用号是通过eax寄存器传递给内核的。在陷人内核之前，先将系统调用号存入eax中，这样系统调用处理程序一旦运行，就可以从 eax中得到调用号。"
                    }
                ]
            },
            "bbox": [
                144,
                643,
                847,
                702
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. 系统调用服务例程"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                712,
                389,
                728
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "每个系统调用都对应一个内核服务例程来实现该系统调用的具体功能，其命名格式都是以“sys_”开头，如 sys_read 等，其代码实现通常存放在./kernel/sys.c文件中。服务例程的原型声明则是在/include/linux/syscalls.h 中，通常都有固定的格式，如 sys_open 的原型为："
                    }
                ]
            },
            "bbox": [
                144,
                744,
                847,
                804
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "asmlinkage long sys_open(const char __user *filename,int flags, int mode); "
                    }
                ]
            },
            "bbox": [
                179,
                810,
                724,
                826
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "其中“asmlinkage”是一个必须的限定词，用于通知编译器仅从堆栈中提取该函数的参数，而不是从寄存器中，因为在执行服务例程之前系统已经将通过寄存器传递过来的参数值压入内核堆栈了。在新版本的内核中，引入了宏“SYSCALL_DEFINEN(sname)”对服务例程原型进行了封装，其中的“N”是该系统调用所需要参数的个数，如上述sys_open 调用"
                    }
                ]
            },
            "bbox": [
                144,
                829,
                848,
                910
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在./kernel/sys.c 文件中的实现格式为："
                    }
                ]
            },
            "bbox": [
                144,
                90,
                438,
                105
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode) "
                    }
                ]
            },
            "bbox": [
                179,
                112,
                729,
                128
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如后面添加系统调用示例程序中，服务例程的实现格式为："
                    }
                ]
            },
            "bbox": [
                179,
                131,
                636,
                149
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "SYSCALL_DEFINE0(zwhsyscall) "
                    }
                ]
            },
            "bbox": [
                179,
                155,
                403,
                171
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "本知识点的详细介绍大家可以参考网页："
                    }
                ]
            },
            "bbox": [
                179,
                175,
                494,
                191
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "http://blog.csdn.net/adc0809608/article/details/7417180 "
                    }
                ]
            },
            "bbox": [
                179,
                197,
                601,
                212
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3. 系统调用参数传递"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                223,
                391,
                239
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "与普通函数一样，系统调用通常也需要输入/输出参数。在 x86上，linux通过6 个寄存器来传入参数值，其中eax传递系统调用号，后面5个寄存器ebx, ecx, edx, esi和 edi按照顺序存放前五个参数，需要六个或六个以上参数的情况不多见，此时，应该用一个单独的寄存器存放指向所有这些参数在用户空间地址的指针。服务例程的返回值通过 eax寄存器传递，这是在执行rutern指令时由C 编译器自动完成的。"
                    }
                ]
            },
            "bbox": [
                144,
                255,
                847,
                356
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "当系统调用执行成功时，将返回服务例程的返回值，通常是0。但如果执行失败，为防止和正常的返回值混淆，系统调用并不直接返回错误码，而是将错误码放入一个名为 errno的全局变量中，通常是一个负值，通过调用perror()库函数，可以把errno翻译成用户可以理解的错误信息描述。"
                    }
                ]
            },
            "bbox": [
                144,
                362,
                848,
                442
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4. 系统调用参数验证"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                451,
                389,
                469
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "系统调用必须仔细检查用户传入的参数是否合法有效。比如与进程相关的调用必须检查用户提供的PID等是否有效。"
                    }
                ]
            },
            "bbox": [
                144,
                483,
                842,
                521
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "最重要的是要检查用户提供的指针是否有效，以防止用户进程非法访问数据。内核提供了两个函数来完成必须的检查以及内核空间与用户空间之间数据的来回拷贝："
                    }
                ]
            },
            "bbox": [
                144,
                527,
                842,
                563
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "copy_to_user()和 copy_from_user()，在较低内核版本中，定义在./arch/x86/lib/usercopy_32.c文件中；对于内核 4.12，定义在./include/linux/uaccess.h 文件中："
                    }
                ]
            },
            "bbox": [
                144,
                570,
                847,
                606
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1） copy_to_user()："
                    }
                ]
            },
            "bbox": [
                189,
                609,
                363,
                626
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "static __always_inline unsigned long __must_check "
                    }
                ]
            },
            "bbox": [
                198,
                633,
                574,
                648
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "copy_to_user(void __user *to, const void *from, unsigned long n); "
                    }
                ]
            },
            "bbox": [
                200,
                653,
                680,
                670
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "功能：将数据块从内核空间复制到用户空间"
                    }
                ]
            },
            "bbox": [
                200,
                674,
                539,
                689
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "参数含义："
                    }
                ]
            },
            "bbox": [
                200,
                696,
                280,
                711
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "to：用户进程空间中的目的地址；"
                    }
                ]
            },
            "bbox": [
                215,
                717,
                473,
                732
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "from：内核空间的源地址"
                    }
                ]
            },
            "bbox": [
                215,
                739,
                415,
                753
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "n：需要拷贝的数据长度(字节数)。"
                    }
                ]
            },
            "bbox": [
                216,
                760,
                478,
                775
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "返回值：函数执行成功返回 0；如果失败，则返回没有拷贝成功的字节数。"
                    }
                ]
            },
            "bbox": [
                196,
                781,
                771,
                796
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（2） copy_from_user()"
                    }
                ]
            },
            "bbox": [
                189,
                800,
                376,
                816
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "static __always_inline unsigned long __must_check "
                    }
                ]
            },
            "bbox": [
                198,
                822,
                574,
                838
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "copy_from_user(void *to, const void __user *from, unsigned long n); "
                    }
                ]
            },
            "bbox": [
                200,
                844,
                700,
                859
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "功能：将数据块从用户空间复制到内核空间"
                    }
                ]
            },
            "bbox": [
                200,
                864,
                539,
                879
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "参数含义："
                    }
                ]
            },
            "bbox": [
                200,
                885,
                280,
                900
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "to：内核空间的目的地址；"
                    }
                ]
            },
            "bbox": [
                213,
                90,
                420,
                105
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "from：用户空间的源地址"
                    }
                ]
            },
            "bbox": [
                213,
                112,
                415,
                126
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "n：需要拷贝的数据长度(字节数)。"
                    }
                ]
            },
            "bbox": [
                213,
                133,
                477,
                148
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "返回值：函数执行成功返回 0；如果失败，则返回没有拷贝成功的字节数。"
                    }
                ]
            },
            "bbox": [
                196,
                154,
                771,
                170
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1．3 Linux 添加系统调用的步骤："
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                195,
                529,
                214
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "这里以一个很简单的例子说明 linux中添加一个新的系统调用的步骤，该调用没有输入参数，名字叫“zwhsyscall”。采用的内核版本是最新的4.12，x86 平台、64位。注意必须以root身份才能完成下述操作。"
                    }
                ]
            },
            "bbox": [
                144,
                244,
                847,
                303
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. 分配系统调用号，修改系统调用表"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                313,
                529,
                331
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "查看系统调用表（./arch/x86/entyr/syscalls/syscall_64.tbl），如图 7-16 所示："
                    }
                ]
            },
            "bbox": [
                181,
                347,
                764,
                363
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/a59459d3c0923ce9087c6dd048f4d7e6e1b53bc6ebd4b8ab1daef9f8c4406e39.jpg"
                },
                "image_caption": [
                    {
                        "type": "text",
                        "content": "图7-16 系统调用表部分内容"
                    }
                ],
                "image_footnote": []
            },
            "bbox": [
                184,
                363,
                887,
                491
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "每个系统调用在表中占一表项，其格式为："
                    }
                ]
            },
            "bbox": [
                181,
                519,
                510,
                535
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "<系统调用号> <commom/64/x32> <系统调用名 "
                    },
                    {
                        "type": "equation_inline",
                        "content": "> <"
                    },
                    {
                        "type": "text",
                        "content": "<服务例程入口地址>"
                    }
                ]
            },
            "bbox": [
                179,
                541,
                712,
                556
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "选择一个未使用的系统调用号进行分配，比如当前系统使用到 332 号，则新添加的系统调用可使用333号。确定调用号后，应在系统调用表中关联新调用的调用号与服务例程入口，即在syscall_64.tbl文件中为新调用添加一条记录，修改结果如图7-17所示："
                    }
                ]
            },
            "bbox": [
                144,
                562,
                842,
                621
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/efd0422062519c1226de617798fa474fd3a1b02219447cdd3caaf03884ed5d62.jpg"
                },
                "image_caption": [
                    {
                        "type": "text",
                        "content": "图 7-17 修改系统调用表"
                    }
                ],
                "image_footnote": []
            },
            "bbox": [
                151,
                627,
                833,
                726
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. 申明系统调用服务例程原型"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                763,
                470,
                780
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux 系统调用服务例程的原型声明在文件 linux-4.12/include/linux/syscalls.h 中，可在文件末尾添加如图7-18 所示内容："
                    }
                ]
            },
            "bbox": [
                144,
                796,
                847,
                832
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/9e858592f4080a0633cfc441808778dbc28597710536a8c77d13c01e9a8ad6e2.jpg"
                },
                "image_caption": [
                    {
                        "type": "text",
                        "content": "图 7-18 声明系统调用服务例程原型"
                    }
                ],
                "image_footnote": []
            },
            "bbox": [
                184,
                840,
                236,
                864
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "asmlinkage long sys_zwhsyscall(void); "
                    }
                ]
            },
            "bbox": [
                243,
                844,
                586,
                860
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                63
            ]
        }
    ],
    [
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3.实现系统调用服务例程"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                93,
                418,
                110
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "下面为新调用 zwhsyscall 编写服务例程 sys_zwhsyscall，通常添加在 sys.c 文件中，其完整路径为：linux-4.12/kernel/sys.c，如图 7-19 所示："
                    }
                ]
            },
            "bbox": [
                144,
                126,
                845,
                162
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/afdc250564f749d75b4dad48af714b9f7481ac457d05a22252977b108081e5ee.jpg"
                },
                "image_caption": [
                    {
                        "type": "text",
                        "content": "图 7-19 编写系统调用服务例程"
                    }
                ],
                "image_footnote": []
            },
            "bbox": [
                184,
                168,
                694,
                252
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4. 重新编译内核"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                288,
                349,
                305
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "上面三个步骤已经完成添加一个新系统调用的所有工作，但是要让这个系统调用真正在内核中运行起来，还需要重新编译内核。有关内核编译的知识，见7.2.4 节的介绍。"
                    }
                ]
            },
            "bbox": [
                144,
                321,
                838,
                357
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5. 编写用户态程序测试新系统调用"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                368,
                509,
                384
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "可编写一个用户态程序来调用上面新添加的系统调用："
                    }
                ]
            },
            "bbox": [
                181,
                401,
                600,
                416
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "1 #define _GNU_SOURCE "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "2 #include <linux/unistd.h> "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "3 #include <sys/syscall.h> "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "4 #define __NR_mysyscall 333 /*系统调用号根据实验具体数字而定*/ "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "5 int main() { "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "6 syscall(__NR_mysyscall); /*或 syscall(333) */ "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "7 } "
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                179,
                423,
                749,
                565
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "程序说明："
                    }
                ]
            },
            "bbox": [
                181,
                571,
                263,
                586
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "程序第 6 行使用了 syscall()宏调用新添加的系统调用，它是 linux 提供给用户态程序直接调用系统调用的一种方法，其格式为："
                    }
                ]
            },
            "bbox": [
                144,
                593,
                836,
                630
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "int syscall(int number, ...); "
                    }
                ]
            },
            "bbox": [
                179,
                637,
                373,
                652
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "其中number是系统调用号，number后面应顺序接上该系统调用的所有参数。"
                    }
                ]
            },
            "bbox": [
                179,
                657,
                779,
                673
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "编译该程序并运行后，使用 dmesg命令查看输出内容，如图7-20所示："
                    }
                ]
            },
            "bbox": [
                179,
                678,
                732,
                694
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/9683c7f5a64052a891b7bcf0584365b3f319d43213c32d52f38e9e96807f6ed4.jpg"
                },
                "image_caption": [
                    {
                        "type": "text",
                        "content": "图 7-20 系统调用测试结果"
                    }
                ],
                "image_footnote": []
            },
            "bbox": [
                178,
                696,
                724,
                749
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1．4 Linux 内核编译步骤"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                797,
                453,
                815
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "作为自由软件，linux 内核版本不断更新，新内核会修订旧内核的bug，并增加若干新特性，如支持更多的硬件、具备更好的系统管理能力、运行速度更快、更稳定等。用户若想使用这些新特性，或希望根据自身系统需求定制一个更高效、更稳定的内核，就需要重"
                    }
                ]
            },
            "bbox": [
                144,
                847,
                838,
                904
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "新编译内核。下面以linux初学者喜欢使用的ubuntu系统为例，介绍内核编译步骤。"
                    }
                ]
            },
            "bbox": [
                144,
                90,
                793,
                105
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1.实验环境"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                116,
                299,
                131
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Ubuntu 64 位：ubuntu-16.04-desktop-amd64.iso，待编译的新内核是 linux-4.12.tar.xz。"
                    }
                ]
            },
            "bbox": [
                179,
                148,
                830,
                164
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "虚拟机：WMware-player-12.1.1-3770994.exe "
                    }
                ]
            },
            "bbox": [
                181,
                170,
                524,
                185
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "虚拟机的建议配置参数：磁盘空间 "
                    },
                    {
                        "type": "equation_inline",
                        "content": "3 0 6 8 { \\sim } 4 0 6 8"
                    },
                    {
                        "type": "text",
                        "content": "以上，内存2GB以上。由于在内核编译过程中会生成较多的临时文件，如果磁盘空间预留太小，会出现磁盘空间不足的错误而导致内核编译失败；内存太小会影响编译速度，一般内核编译时间是 "
                    },
                    {
                        "type": "equation_inline",
                        "content": "1 . 5 \\mathsf { h } { \\sim } 3 \\mathsf { h }"
                    },
                    {
                        "type": "text",
                        "content": "。"
                    }
                ]
            },
            "bbox": [
                144,
                191,
                842,
                249
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2.下载内核源码"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                260,
                339,
                275
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux的内核源代码是完全公开的，有很多网站都提供源码下载，推荐使用 linux的官方网站：http://www.kernel.org，在这里可以找到所有的内核版本，如图 7-21 所示："
                    }
                ]
            },
            "bbox": [
                144,
                292,
                847,
                329
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/c94095dac0782a7653400af87d218cb03e86cf4444184127fe8d1268e397de54.jpg"
                },
                "image_caption": [
                    {
                        "type": "text",
                        "content": "图 7-21 linux 官方网站"
                    }
                ],
                "image_footnote": []
            },
            "bbox": [
                184,
                332,
                890,
                551
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3.解压缩内核源码文件"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                583,
                400,
                600
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "首先切换到 root 用户，将下载的新内核压缩文件复制到/home 或其他比较空闲的目录中，然后进入压缩文件所在子目录，分两步解压缩："
                    }
                ]
            },
            "bbox": [
                144,
                612,
                848,
                646
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1） # xz -d linux-4.4.19.tar.xz 大概执行 1 分钟左右，中间没有任何信息显示。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2） # tar -xvf linux-4.4.19.tar"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                200,
                649,
                808,
                682
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "注意：由于编译过程中会生成很多临时文件，所以要确保压缩文件所在子目录有足够的空闲空间，最好能有15-20GB。笔者在建立虚拟机时预留了40GB磁盘空间。"
                    }
                ]
            },
            "bbox": [
                144,
                686,
                848,
                720
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4. 清除残留的.config 和.o 文件"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                732,
                492,
                749
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "当编译出错需要重新编译或不是第一次编译，都需要清除残留的.config 和.o 文件，方法是进入linux-4.12子目录，执行以下命令："
                    }
                ]
            },
            "bbox": [
                144,
                760,
                848,
                794
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "# make mrproper "
                    }
                ]
            },
            "bbox": [
                250,
                797,
                396,
                813
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "这里可能会提醒安装 ncurses 包，在 ubuntu 中 ncurses 库的名字是 libncurses5-dev，所以安装命令是："
                    }
                ]
            },
            "bbox": [
                144,
                816,
                848,
                848
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#apt-get install libncurses5-dev "
                    }
                ]
            },
            "bbox": [
                250,
                854,
                480,
                869
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "安装完成后再次执行：# make mrproper"
                    }
                ]
            },
            "bbox": [
                181,
                876,
                489,
                891
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5. 配置内核"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                93,
                309,
                110
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "运行命令：# make menuconfig "
                    }
                ]
            },
            "bbox": [
                181,
                123,
                416,
                137
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "运行该命令过程中，可能会出现如图 7-22 所示错误信息："
                    }
                ]
            },
            "bbox": [
                181,
                141,
                621,
                155
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "root@ubuntu:/usr/src/linux-source-4.4.0# make menuconfig  \nHOSTCC scripts/basic/fixdep  \nHOSTCC scripts/kconfig/mconf.o  \nIn file included from scripts/kconfig/mconf.c:23:0:  \nscripts/kconfig/lxdialog/dialog.h:38:20: fatal error: curses.h: No such file or directory  \ncompilation terminated.  \nscripts/Makefile.host:108: recipe for target 'scripts/kconfig/mconf.o' failed  \nmake[1]: *** [scripts/kconfig/mconf.o] Error 1  \nMakefile:541: recipe for target 'menuconfig' failed  \nmake: *** [menuconfig] Error 2 "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                184,
                160,
                845,
                287
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "图 7-22 缺少套件 ncurses devel 的错误信息"
                    }
                ]
            },
            "bbox": [
                181,
                290,
                467,
                304
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "这是因为 Ubuntu 系统中可能缺少一个套件 ncurses devel，安装方法是执行命令："
                    }
                ]
            },
            "bbox": [
                179,
                307,
                796,
                324
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "apt-get install libncurses5-dev "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                181,
                328,
                413,
                342
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "之后再执行“make menuconfig”命令将打开如图 7-23 所示配置对话框，对于每一个配置选项，用户可以回答\"y\"、\"m\"或\"n\"：其中\"y\"表示将相应特性的支持或设备驱动程序编译进内核；\"m\"表示将相应特性的支持或设备驱动程序编译成可加载模块，在需要时，可由系统或用户自行加入到内核中去；\"n\"表示内核不提供相应特性或驱动程序的支持。一般采用默认值即可：选择<save>保存配置信息，然后选择<exit>退出对话框。"
                    }
                ]
            },
            "bbox": [
                144,
                344,
                847,
                434
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/f3f60ad7499943aa7850542d05627738e94d1d47df174b2a3141aa476ffa809e.jpg"
                },
                "image_caption": [
                    {
                        "type": "text",
                        "content": "图 7-24 编译错误"
                    }
                ],
                "image_footnote": []
            },
            "bbox": [
                184,
                438,
                768,
                656
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "图 7-23 配置内核界面"
                    }
                ]
            },
            "bbox": [
                438,
                659,
                589,
                674
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "6. 编译内核，生成启动映像文件"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                687,
                490,
                703
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "内 核 配 置 完 成 后 ， 编 译 内 核 ， 并 生 成 启 动 映 像 文 件 bzImage （ 位于./arch/x86_64/boot/bzImage）："
                    }
                ]
            },
            "bbox": [
                144,
                715,
                848,
                750
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "执行命令：# make "
                    }
                ]
            },
            "bbox": [
                181,
                753,
                326,
                766
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如果是多核cpu可使用 make -j来加快编译速度。可能会出现图7-24 所示的错误："
                    }
                ]
            },
            "bbox": [
                181,
                771,
                811,
                785
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "CALE scripts/checksyscalts.sh   \nHOSTCC scripts/sign-file   \nscripts/sign-file.c:23:30: fatal error:openssl/opensslv.h: No such file or direc tory "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                181,
                793,
                873,
                837
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "这是因为没有安装 openssl， openssl 的安装方法是："
                    }
                ]
            },
            "bbox": [
                179,
                864,
                584,
                879
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "执行命令：# apt-get install libssl-dev "
                    }
                ]
            },
            "bbox": [
                181,
                883,
                455,
                898
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "openssl安装完成后，再执行 make 命令即可，需要较长时间，笔者4核处理器，用了约 20 分钟。"
                    }
                ]
            },
            "bbox": [
                144,
                90,
                843,
                127
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "7. 编译模块"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                137,
                309,
                154
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "执行命令：# make modules "
                    }
                ]
            },
            "bbox": [
                181,
                166,
                394,
                180
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "第一次编译模块需要很长时间，笔者大概用了两个半小时。"
                    }
                ]
            },
            "bbox": [
                179,
                184,
                635,
                199
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "8. 安装内核"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                211,
                309,
                227
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）安装模块：# make modules_install"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）安装内核：#make install"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                240,
                487,
                273
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "9.配置 grub 引导程序"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                286,
                388,
                302
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "只需要执行命令：# update-grub2，该命令会自动修改 grub。"
                    }
                ]
            },
            "bbox": [
                181,
                313,
                640,
                330
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "10.重启系统"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                341,
                310,
                357
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "执行命令：# reboot "
                    }
                ]
            },
            "bbox": [
                181,
                370,
                337,
                384
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "将使用新内核启动 linux。启动完成后进入终端查看内核版本，如图7-25 所示："
                    }
                ]
            },
            "bbox": [
                179,
                388,
                784,
                403
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "zwh@ubuntu:~$ uname -a Linuxubuntu 4.12.0 #1 SMP Sat Jul 8 20:23:38 PDT 2017 x86_64 x86_64 x86_64 GNU/Linux zwh@ubuntu:~$ "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                149,
                407,
                850,
                458
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "图 7-25 查看内核版本"
                    }
                ]
            },
            "bbox": [
                344,
                463,
                502,
                476
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "实验二 linux 内核模块编程"
                    }
                ],
                "level": 1
            },
            "bbox": [
                309,
                556,
                702,
                580
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2.1 设计目的和内容要求"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                612,
                470,
                631
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1．设计目的"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                668,
                285,
                682
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux提供的模块机制能动态扩充linux功能而无需重新编译内核，已经广泛应用在linux内核的许多功能的实现中。在本实验中将学习模块的基本概念、原理及实现技术，然后利用内核模块编程访问进程的基本信息，从而加深对进程概念的理解、对模块编程技术的掌握。"
                    }
                ]
            },
            "bbox": [
                144,
                695,
                845,
                766
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2．内容要求"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                778,
                285,
                794
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1） 设计一个模块，要求列出系统中所有内核线程的程序名、PID号、进程状态及进程优先级。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2） 设计一个带参数的模块，其参数为某个进程的 PID号，该模块的功能是列出该进程的家族信息，包括父进程、兄弟进程和子进程的程序名、PID号。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3） 请根据自身情况，进一步阅读分析程序中用到的相关内核函数的源码实现。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                807,
                845,
                896
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                63
            ]
        }
    ],
    [
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3. 学时安排（共 4 学时）"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                95,
                381,
                110
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4． 开发平台"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                131,
                294,
                148
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux 环境，gcc，gdb，vim 或 gedit 等。"
                    }
                ]
            },
            "bbox": [
                216,
                160,
                519,
                175
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2.2 linux 内核模块简介"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                202,
                465,
                222
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2.2.1 线程基本概念"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                256,
                374,
                274
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux 内核是单体式结构，相对于微内核结构而言，其运行效率高，但系统的可维护性及可扩展性较差。为此，linux 提供了内核模块（module）机制，它不仅可以弥补单体式内核相对于微内核的一些不足，而且对系统性能没有影响。内核模块的全称是动态可加载内核模块（Loadable Kernel Module,KLM），简称为模块。模块是一个目标文件，能完成某种独立的功能，但其自身不是一个独立的进程，不能单独运行，可以动态载入内核，使其成为内核代码的一部分，与其他内核代码的地位完全相同。当不需要某模块功能时，可以动态卸载。实际上，linux 中大多数设备驱动程序或文件系统都以模块方式实现，因为它们数目繁多，体积庞大，不适合直接编译在内核中，而是通过模块机制，需要时临时加载。使用模块机制的另一个好处是，修改模块代码后只需重新编译和加载模块，不必重新编译内核和引导系统，降低了系统功能的更新难度。"
                    }
                ]
            },
            "bbox": [
                144,
                286,
                852,
                467
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "一个模块通常由一组函数和数据结构组成，用来实现某种功能，如实现一种文件系统、一个驱动程序或其他内核上层的功能。模块自身不是一个独立的进程，当前进程运行是调用到模块代码时，可以认为该段代码就代表当前进程在核心态运行。"
                    }
                ]
            },
            "bbox": [
                144,
                470,
                850,
                524
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2.2.2 内核符号表"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                535,
                359,
                552
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "模块编程可以使用内核的一些全局变量和函数，内核符号表就是用来存放所有模块都可以访问的符号及相应地址的表，其存放位置在/proc/kallsyms 文件中，我们可以使用“cat/proc/kallsyms”命令查看当前环境下导出的内核符号。"
                    }
                ]
            },
            "bbox": [
                144,
                563,
                850,
                615
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "通常情况下，一个模块只需实现自己的功能，而无需导出任何符号；但如果其他模块需要调用这个模块的函数或数据结构时，该模块也可以导出符号。这样，其他模块可以使用由该模块导出的符号，利用现成的代码实现更加复杂的功能，这种技术也称作模块层叠技术，当前已经使用在很多主流的内核源代码中。"
                    }
                ]
            },
            "bbox": [
                144,
                619,
                848,
                690
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如果一个模块需要向其他模块导出符号，可使用下面的宏："
                    }
                ]
            },
            "bbox": [
                181,
                693,
                636,
                709
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EXPORT_SYMBOL(symbol_name)；"
                    }
                ]
            },
            "bbox": [
                181,
                713,
                430,
                728
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EXPORT_SYMOBL_GPL(symbol_name)；"
                    }
                ]
            },
            "bbox": [
                181,
                732,
                467,
                747
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "这两个宏均用于将给定的符号导出到模块外部。_GPL版本使得要导出的符号只能被GPL许可证下的模块使用。符号必须在模块文件的全局部分导出，不能在模块中的某个函数中导出。"
                    }
                ]
            },
            "bbox": [
                144,
                749,
                850,
                802
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2.3 内核模块编程基础"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                829,
                435,
                848
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "我们以一个简单的“hello world”模块的实现为例，来说明内核模块的编写结构、编译及加载过程。"
                    }
                ]
            },
            "bbox": [
                146,
                875,
                850,
                909
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2.3.1 模块代码结构"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                93,
                379,
                110
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "“hello world”的示例代码如下："
                    }
                ]
            },
            "bbox": [
                188,
                123,
                433,
                137
            ]
        },
        {
            "type": "algorithm",
            "content": {
                "algorithm_caption": [],
                "algorithm_content": [
                    {
                        "type": "text",
                        "content": "1 #include <linux/init.h>   \n2 #include <linux/module.h>   \n3 #include <linux/kernel.h>   \n4   \n5 static int hello_init(void)   \n6 {   \n7  "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\mathrm{printk}(\\mathrm{KERN\\_ALERT}\"hello,\\mathrm{world}\\backslash \\mathrm{n\"});"
                    },
                    {
                        "type": "text",
                        "content": "   \n8 return 0;   \n9 }   \n10 static void hello_exit(void)   \n11 {   \n12  "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\mathrm{printk}(\\mathrm{KERN\\_ALERT}\"goodbye\\backslash n\")"
                    },
                    {
                        "type": "text",
                        "content": "   \n13 }   \n14   \n15 module_init(hello_init);   \n16 module_exit(hello_exit);   \n17 MODULE licenses(\"GPL\");"
                    }
                ]
            },
            "bbox": [
                181,
                142,
                519,
                454
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "上面的代码是一个内核模块的典型结构。该模块被载入内核时会向系统日志文件中写入“hello，world”；当被卸载时，也会向系统日志中写入“goodbye”。下面说明该模块代码的结构组成："
                    }
                ]
            },
            "bbox": [
                144,
                475,
                848,
                527
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（1） 头文件声明："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                531,
                342,
                545
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "第1、2 行是模块编程的必需头文件。module.h包含了大量加载模块所需要的函数和符号的定义；init.h 包含了模块初始化和清理函数的定义。如果模块在加载时允许用户传递参数，模块还应该包含 moduleparam.h 头文件。"
                    }
                ]
            },
            "bbox": [
                144,
                549,
                848,
                602
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（2） 模块许可申明："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                605,
                359,
                619
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "第 17 行是模块许可声明。Linux 内核从 2.4.10 版本内核开始，模块必须通过MODULE_LICENSE 宏声明此模块的许可证，否则在加载此模块时，会收到内核被污染 “kerneltainted” 的警告。从 linux/module.h 文件中可以看到，被内核接受的有意义的许可证有 “GPL”，“GPL v2”，“GPL and additional rights”，“Dual BSD/GPL”，“Dual MPL/GPL”，“Proprietary”，其中“GPL” 是指明这是 GNU General Public License 的任意版本，其他许可证大家可以查阅资料进一步了解。MODULE_LICENSE 宏声明可以写在模块的任何地方（但必须在函数外面），不过惯例是写在模块最后。"
                    }
                ]
            },
            "bbox": [
                144,
                623,
                853,
                750
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（3） 初始化与清理函数的注册："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                753,
                448,
                768
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "内核模块程序中没有 main函数，每个模块必须定义两个函数：一个函数用来初始化（示例第 5 行），主要完成模块注册和申请资源，该函数返回 0，表示初始化成功，其他值表示失败；另一个函数用来退出（示例第 10 行），主要完成注销和释放资源。Linux 调用宏module_init 和 module_exit 来注册这两个函数，如示例中第 15、16 两行代码，module_init宏标记的函数在加载模块时调用，module_exit 宏标记的函数在卸载模块时调用。需要注意的是，初始化与清理函数必须在宏 module_init和 module_exit使用前定义，否则会出现编译错误。"
                    }
                ]
            },
            "bbox": [
                144,
                771,
                850,
                898
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "初始化函数通常定义为：  \nstatic int __init init_func(v{ //初始化代码} module_init(init_func);"
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                181,
                85,
                369,
                195
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "一般情况下，初始化函数应当申明为 static，以便它们不会在特定文件之外可见。如果该函数只是在初始化使用一次，可在声明语句中加__init标识，则模块在加载后会丢弃这个初始化函数，释放其内存空间。"
                    }
                ]
            },
            "bbox": [
                144,
                197,
                848,
                249
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "清理函数通常定义为：  \nstatic void __exit exit_fu{//清理代码}  \nmodule_exitexit_func);"
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                181,
                252,
                359,
                361
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "清理函数没有返回值，因此被声明为 void。声明语句中的__exit的含义与初始化函数中的__init 类似，不再重述。"
                    }
                ]
            },
            "bbox": [
                144,
                363,
                847,
                398
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "一个基本的内核模块只要包含上述三个部分就可以正常工作了。"
                    }
                ]
            },
            "bbox": [
                181,
                401,
                670,
                416
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（4） printk()函数说明："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                420,
                376,
                435
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "大家可能已经发现在代码第 3行还有一个头文件“<linux/kernel.h”，这不是模块编程必须的，而是因为我们在代码中使用了printk()函数（第7、12 行），在该头文件中包含了 printk()的定义。"
                    }
                ]
            },
            "bbox": [
                144,
                438,
                848,
                489
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Printk()会依据日志级别将指定信息输出到控制台或日志文件中，其格式为："
                    }
                ]
            },
            "bbox": [
                179,
                494,
                757,
                508
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "printk(日志级别 \"消息文本\")；"
                    }
                ]
            },
            "bbox": [
                181,
                512,
                410,
                527
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如 printk(KERN_ALERT\"hello,world\\n\");"
                    }
                ]
            },
            "bbox": [
                181,
                532,
                470,
                546
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "一般情况下，优先级高于控制台日志级别的消息将被打印到控制台，优先级低于控制台日志级别的消息将被打印到 messages 日志文件中，而在伪终端下不打印任何的信息。有关其更详细的使用说明请大家自行查阅资料学习。"
                    }
                ]
            },
            "bbox": [
                144,
                549,
                848,
                601
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "加载模块后，用户可使用 dmesg命令查看模块初始化函数中的输出信息，如使用“dmesg| tail -20”来输出“dmesg”命令的最后 20 行日志。"
                    }
                ]
            },
            "bbox": [
                144,
                605,
                848,
                639
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "最后总结一下内核模块程序源码的组成："
                    }
                ]
            },
            "bbox": [
                181,
                642,
                492,
                657
            ]
        },
        {
            "type": "table",
            "content": {
                "image_source": {
                    "path": "images/8c5696582781d2d9cd88646275c972203e093f0e15447f6f98aec1b46b5fa5ad.jpg"
                },
                "table_caption": [],
                "table_footnote": [],
                "html": "<table><tr><td>头文件:</td><td>#include&lt;linux/init.h&gt;#include&lt;linux/module.h</td><td>必选</td></tr><tr><td>许可声明</td><td>MODULE_LICENSE(&quot;Dual BSD/GPL&quot;)</td><td>必选</td></tr><tr><td>加载函数</td><td>static int __init hello_init(void)</td><td>必选</td></tr><tr><td>卸载函数</td><td>static void __exit hello_exit(void)</td><td>必选</td></tr><tr><td>模块参数</td><td>moduleparam(name,type,perm)</td><td>可选</td></tr><tr><td>模块导出符号</td><td>EXPORT_SYMBOL(符号名)</td><td>可选</td></tr><tr><td>模块作者等信息</td><td>MODULE_AUTHOR(&quot;作者名&quot;)</td><td>可选</td></tr></table>",
                "table_type": "simple_table",
                "table_nest_level": 1
            },
            "bbox": [
                194,
                658,
                783,
                813
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2.3.2 模块编译和加载"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                840,
                400,
                857
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. 模块编译的 Makefile 文件："
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                878,
                420,
                892
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在linux2.6 及之后的内核中，模块的编译需要配置过的内核源代码，否则无法进行模块的编译工作；编译、链接后生成的内核模块后缀为.ko；编译过程首先会都内核源目录下读取顶层的 Makefile 文件（注意第一个字母“M”需要大写），然后返回模块源代码所在的目录继续编译。"
                    }
                ]
            },
            "bbox": [
                144,
                85,
                848,
                156
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在使用make命令编译模块代码时，应先书写 Makefile 文件，且应放在模块源代码文件所在目录中。针对上面的“hello world”模块，编写的一个简单 Makefile："
                    }
                ]
            },
            "bbox": [
                144,
                160,
                848,
                193
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "1 obj-m :=hello.o //生成的模块名称是：hello.ko"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "2 KDIR :=/lib/modules/$(shell uname -r)/build "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "3 PWD :=$(shell pwd) // PWD 是当前目录"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "4 default: "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "5 make -C $(KDIR) "
                            },
                            {
                                "type": "equation_inline",
                                "content": "M = S"
                            },
                            {
                                "type": "text",
                                "content": "(PWD) modules // -C 指定内核源码目录，M 指定模块源码目录"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "6 clean: "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "7 make -C $(KDIR) M=$(PWD) clean "
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                197,
                845,
                323
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "其中：KDIR 是内核源码目录，该目录通过当前运行内核使用的模块目录中的build符号链接指定。或者直接给出源码目录也可以，如：KDIR : "
                    },
                    {
                        "type": "equation_inline",
                        "content": ": ="
                    },
                    {
                        "type": "text",
                        "content": "/usr/src/linux-headers-4.4.0-36-generic."
                    }
                ]
            },
            "bbox": [
                144,
                326,
                848,
                361
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "需要注意的是，在第 5 行和第 7 行的“make”之前应该是“tab”键，而不是空格。"
                    }
                ]
            },
            "bbox": [
                181,
                363,
                820,
                379
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. 由多个文件构成的内核模块的 Makefile 文件："
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                392,
                561,
                407
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "当模块的功能较多时，把模块的源代码分成几个文件是一个明智的选择，如下面的示例："
                    }
                ]
            },
            "bbox": [
                181,
                419,
                847,
                435
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "hello1print.c:  \n#include <linux/init.h>  \n#include <linux/module.h>  \n#include <linux/kernel.h>  \nMODULE_LICENSE(\"GPL\");  \nvoid hello2print(void); //来源于第二个.c文件：hello2print.c"
                    }
                ],
                "code_language": "cpp"
            },
            "bbox": [
                181,
                439,
                653,
                548
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "static int __init hello_init(void)   \n{ printf(KERN_ALERT\"hello,world\\n\"); hello2print(); return 0;   \n}   \nstatic void _exit hello_exit(void)   \n{ printf(KERN_ALERT\"goodbye\\n\");   \n}   \nmodule_init(hello_init); module_exit(hello_exit);   \nhello2print.c   \n#include \"linux/kernel.h\"   \nvoid hello2print(void)"
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                181,
                567,
                485,
                900
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "{ printk(KERN_ALERT\"this is hello2 print\\n\"); } "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                179,
                86,
                529,
                139
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "则 Makefile 相应的行改为： obj-m :=hello.ohello-objs :=hello1print.o hello2print.o"
                    }
                ]
            },
            "bbox": [
                181,
                160,
                694,
                193
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "其中含有 module_init(hello_init);module_exit(hello_exit);这两个宏的.o 模块应放在开始。完整的Makefile 文件内容为："
                    }
                ]
            },
            "bbox": [
                144,
                197,
                845,
                230
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "1 obj-m :=hello2.o //生成的模块名称是：hello2.ko"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "2 hello2-objs :=hello1print.o hello2print.o "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "3 KDIR :=/lib/modules/$(shell uname -r)/build "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "4 PWD : "
                            },
                            {
                                "type": "equation_inline",
                                "content": ": = \\$ 5"
                            },
                            {
                                "type": "text",
                                "content": "(shell pwd) // PWD 是当前目录"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "5 default: "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "6 make -C $(KDIR) "
                            },
                            {
                                "type": "equation_inline",
                                "content": "M = S"
                            },
                            {
                                "type": "text",
                                "content": "(PWD) modules // -C 指定内核源码目录，M 指定模块源码目录"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "7 clean: "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "8 make -C $(KDIR) M=$(PWD) clean "
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                234,
                845,
                379
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "注意：1）第 1 行和第 2 行中的“hello2”必须名字相同，表示模块 hello2 的目标文件来源于 hello1print.o 和 hello2print.o。2）在第 6 行和第 8 行的“make”之前应该是“tab”键，而不是空格。"
                    }
                ]
            },
            "bbox": [
                144,
                382,
                847,
                434
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3. 相关操作命令："
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                447,
                324,
                462
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "以下命令除 make 命令外，其他都应以 root 用户执行："
                    }
                ]
            },
            "bbox": [
                181,
                475,
                598,
                489
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1） 模块编译命令 make："
                    }
                ]
            },
            "bbox": [
                186,
                494,
                401,
                508
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "命令格式：$make "
                    }
                ]
            },
            "bbox": [
                181,
                512,
                322,
                526
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "不带参数的make命令将默认当前目录下名为makefile或者名为Makefile的文件为描述文件。"
                    }
                ]
            },
            "bbox": [
                144,
                531,
                847,
                564
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（2） 加载模块命令 insmod 或 modprobe："
                    }
                ]
            },
            "bbox": [
                186,
                568,
                517,
                582
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "insmod 命令把需要载入的模块以目标代码的形式加载到内核中，将自动调用init_module 宏。其格式为："
                    }
                ]
            },
            "bbox": [
                144,
                586,
                847,
                620
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "# insmod [filename] [module options...] "
                    }
                ]
            },
            "bbox": [
                181,
                624,
                470,
                639
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Modprobe 命令的功能与 insmod 一样，区别在于 modprobe 能够处理 module 载入的相依问题，其格式为："
                    }
                ]
            },
            "bbox": [
                144,
                642,
                847,
                675
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "# modprobe [module options...] [modulename] [module parameters...] "
                    }
                ]
            },
            "bbox": [
                179,
                680,
                707,
                694
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如本示例中加载模块的命令为：# insmod hello.ko"
                    }
                ]
            },
            "bbox": [
                181,
                697,
                559,
                712
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（3） 查看模块命令 lsmod："
                    }
                ]
            },
            "bbox": [
                189,
                715,
                400,
                730
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "列出当前所有已载入系统的模块信息，包括模块名、大小、其他模块的引用计数等信息。命令格式：# lsmod"
                    }
                ]
            },
            "bbox": [
                201,
                734,
                847,
                766
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "通常会配合 grep 来查看指定模块是否已经加载：# lsmod | grep 模块名"
                    }
                ]
            },
            "bbox": [
                179,
                771,
                727,
                785
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（5） 卸载模块命令 rmmod："
                    }
                ]
            },
            "bbox": [
                189,
                791,
                416,
                804
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "卸载已经载入内核的指定模块，格式为："
                    }
                ]
            },
            "bbox": [
                181,
                809,
                492,
                822
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "# rmmod 模块名"
                    }
                ]
            },
            "bbox": [
                181,
                827,
                312,
                841
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4. 带参数的模块编程"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                854,
                352,
                869
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "有时候用户需要向模块传递一些参数，如使用模块机制实现设备驱动程序时，用户可能"
                    }
                ]
            },
            "bbox": [
                179,
                882,
                847,
                897
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "希望在不同条件下让设备在不同状态下工作。"
                    }
                ]
            },
            "bbox": [
                144,
                85,
                494,
                101
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1） 头文件："
                    }
                ]
            },
            "bbox": [
                189,
                105,
                307,
                118
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "模块要带参数，则头文件必须包括：#include <linux/moduleparam.h>。"
                    }
                ]
            },
            "bbox": [
                181,
                123,
                712,
                137
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（2） module_param ()宏"
                    }
                ]
            },
            "bbox": [
                189,
                142,
                389,
                158
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "module_param ()宏的功能是在加载模块时或者模块加载以后传递参数给模块，其格式为： module_param(name,type,perm); "
                    }
                ]
            },
            "bbox": [
                144,
                160,
                855,
                193
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "其中：name:模块参数的名称"
                    }
                ]
            },
            "bbox": [
                181,
                197,
                408,
                211
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "type: 模块参数的数据类型"
                    }
                ]
            },
            "bbox": [
                233,
                216,
                443,
                231
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "perm: 模块参数的访问权限"
                    }
                ]
            },
            "bbox": [
                233,
                234,
                450,
                249
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "更加详细的内容请大家参考其他资料自学。"
                    }
                ]
            },
            "bbox": [
                181,
                252,
                510,
                268
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "程序中首先将所有需要获取参数值的变量声明为全局变量；然后使用宏 module_param ()对所有参数进行说明，这个宏定义应当放在任何函数之外，典型地是出现在源文件的前面，如下面示例程序中的第8、9两行。"
                    }
                ]
            },
            "bbox": [
                144,
                271,
                855,
                323
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "然后在加载模块的命令行后面跟上参数值即可。注意，必须明确指出哪一个变量的值是多少，否则系统不能判断。如对本示例，可用如下命令加载模块并传递参数："
                    }
                ]
            },
            "bbox": [
                144,
                326,
                848,
                361
            ]
        },
        {
            "type": "algorithm",
            "content": {
                "algorithm_caption": [],
                "algorithm_content": [
                    {
                        "type": "text",
                        "content": "insmod module_parako who  "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\equiv"
                    },
                    {
                        "type": "text",
                        "content": " zwh times  "
                    },
                    {
                        "type": "equation_inline",
                        "content": "= 4"
                    }
                ]
            },
            "bbox": [
                211,
                365,
                534,
                380
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "示例程序："
                    }
                ]
            },
            "bbox": [
                203,
                401,
                285,
                416
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "1 #include<linux/init.h> "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "2 #include<linux/module.h> "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "3 #include<linux/kernel.h> "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "4 #include <linux/moduleparam.h> "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "5 MODULE_LICENSE(\"GPL\");"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "6 static char *who; //参数申明"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "7 static int times; "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "8 module_param(who,char,0644); //参数说明"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "9 module_param(times,int,0644); "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "10 static int __init hello_init(void) "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "11 { "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "12 int i; "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "13 for(i = 1;i <= times;i++) "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "14 printk(\"%d %s!\\n\",i,who); "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "15 return 0; "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "16 } "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "17 static void __exit hello_exit(void)"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "18 { "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "19 printk(\"Goodbye,%s!\\n\",who); "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "20 } "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "21 module_init(hello_init); "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "22 module_exit(hello_exit);"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                205,
                420,
                561,
                824
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2.4 实验指南"
                    }
                ],
                "level": 1
            },
            "bbox": [
                193,
                869,
                339,
                889
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2.4.1 linux 内核链表结构及操作"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                93,
                495,
                111
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "链表是linux内核中最简单、最常用的一种数据结构。Linux内核对链表的实现方式与众不同，它给出了一种抽象链表定义，实际使用中可将其嵌入到其他数据结构中，从而演化出所需要的复杂数据结构。"
                    }
                ]
            },
            "bbox": [
                144,
                123,
                848,
                177
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. 链表的定义："
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                187,
                312,
                203
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "Linux中链表的定义为：  \nstruct list_head{structlist_head \\*next,\\*prev;1"
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                179,
                216,
                431,
                287
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "这个不含数据域的链表，可以嵌入到任何结构中，形成结构复杂的链表，之后就以struct list_head为基本对象，进行链表的插入、删除、合并、遍历等各种操作。如："
                    }
                ]
            },
            "bbox": [
                161,
                288,
                828,
                324
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "struct numlist {\n    int num;\n    struct list_head list;\n}; "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                179,
                326,
                364,
                398
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. 链表的操作"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                410,
                305,
                426
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（1）list_for_each()宏和 list_entry()宏："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                438,
                480,
                454
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux 内核为抽象链表定义了若干操作，如申明及初始化链表、插入节点、删除节点、合并链表、遍历链表等。本实验只涉及读取内核已有链表，所以这里只介绍链表遍历操作，感兴趣的同学可以查看/usr/src/linux4.4.19/include/linux/list.h 文件学习。"
                    }
                ]
            },
            "bbox": [
                161,
                456,
                838,
                508
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "list.h中定义了遍历链表的宏："
                    }
                ]
            },
            "bbox": [
                196,
                512,
                425,
                527
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "/* list_for_each - iterate over a list\n* @pos: the &struct list_head to use as a loop cursor.\n* @head: the head for your list.\n*/\n#define list_for_each(pos, head) \\\nfor (pos = (head) -> next; pos != (head); pos = pos->next) "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                196,
                531,
                616,
                639
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "这个宏仅仅是找到一个个节点在链表中的偏移位置pos，如图2-1 所示："
                    }
                ]
            },
            "bbox": [
                196,
                640,
                747,
                658
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/16e0b5d1d8b750f96f2f0ca9fca4f70df1d53cdfcec3a346d21b668739c668be.jpg"
                },
                "image_caption": [
                    {
                        "type": "text",
                        "content": "图2-1 list_for_each()宏 "
                    }
                ],
                "image_footnote": []
            },
            "bbox": [
                206,
                664,
                440,
                772
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/92220b9c147f7c8f052989864f727a61513e9b59b96a8a33fc4e65df31d5a3ae.jpg"
                },
                "image_caption": [
                    {
                        "type": "text",
                        "content": "图2-2 list_entry()宏"
                    }
                ],
                "image_footnote": []
            },
            "bbox": [
                521,
                665,
                724,
                772
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "问题是，如何通过 pos 获得节点的起始地址，以便引用节点中的其他域？在 list.h 中定义了 list_entry()宏："
                    }
                ]
            },
            "bbox": [
                161,
                809,
                848,
                843
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "/* list_entry - get the struct for this entry "
                    }
                ]
            },
            "bbox": [
                196,
                846,
                497,
                862
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "* @ptr: the &struct list_head pointer. "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "* @type: the type of the struct this is embedded in. "
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                206,
                865,
                591,
                898
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "* @member: the name of the list_head within the struct. "
                    }
                ]
            },
            "bbox": [
                194,
                86,
                640,
                102
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "*/ "
                    }
                ]
            },
            "bbox": [
                206,
                105,
                228,
                118
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#define list_entry(ptr, type, member) \\ container_of(ptr, type, member) "
                    }
                ]
            },
            "bbox": [
                198,
                124,
                480,
                158
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "其中宏 container_of()定义在/usr/src/linux4.4.19/include/linux/kernel.h 中："
                    }
                ]
            },
            "bbox": [
                196,
                160,
                749,
                175
            ]
        },
        {
            "type": "algorithm",
            "content": {
                "algorithm_caption": [],
                "algorithm_content": [
                    {
                        "type": "text",
                        "content": "define container_of(ptr, type, member) {{const typeof((type*)0)->member)\\*mptr = (ptr); "
                    },
                    {
                        "type": "equation_inline",
                        "content": "(type\\*)(char"
                    },
                    {
                        "type": "text",
                        "content": "_mptr - offsetof(type,member));}} "
                    }
                ]
            },
            "bbox": [
                198,
                179,
                611,
                231
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "该宏的功能是计算返回包含 ptr 指向的成员所在的 type 类型数据结构的指针，如图2-2 所示。其实现思路是：计算 type 结构体成员 member 在结构体中的偏移量，然后用ptr 的值减去这个偏移量，就得出 type 数据结构的首地址。"
                    }
                ]
            },
            "bbox": [
                161,
                234,
                848,
                287
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "例如前面定义的链表结构："
                    }
                ]
            },
            "bbox": [
                198,
                290,
                403,
                305
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "struct numlist {\n    int num;\n    struct list_head list;\n}; "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                196,
                309,
                400,
                379
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "可通过如下方式遍历链表的各节点："
                    }
                ]
            },
            "bbox": [
                198,
                382,
                473,
                397
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "struct numlist numhead //链表头节点\nstruct list_head *pos;\nstruct numlist *p;\nlist_for_each(pos, &numhead.list) {\n    p=list_entry(pos, struct numlist, list);\n    //下面可以对p指向的numlist节点进行相关操作\n} "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                196,
                401,
                598,
                527
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（2）list_for_each_entry()宏 /** "
                    }
                ]
            },
            "bbox": [
                191,
                531,
                403,
                564
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "* list_for_each_entry - iterate over list of given type "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "* @pos: the type * to use as a loop cursor. "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "* @head: the head for your list. "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "* @member: the name of the list_struct within the struct. "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "*/ "
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                206,
                568,
                665,
                656
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "define list_for_each_entry(pos, head, member)  \nfor (pos = list_entry((head) -> next, sizeof(*pos), member);  \n    prefetch(pos -> member.next), &pos -> member != (head);  \n    pos = list_entry(pos -> member.next, sizeof(*pos), member)) "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                198,
                661,
                794,
                732
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "该宏实际上是一个 for 循环，利用传入的 pos 作为循环变量，从表头 head 开始，逐项向后（next 方向）移动 pos，直至又回head。prefetch() 可以不考虑，用于预取以提高遍历速度。"
                    }
                ]
            },
            "bbox": [
                144,
                734,
                848,
                785
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2.4.2 进程的 task_struct 结构及家族关系"
                    }
                ],
                "level": 1
            },
            "bbox": [
                200,
                799,
                584,
                815
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux 进程描述符 task_struct 结构定义在/usr/src/linux4.4.19/include/linux/sched.h 中，包含众多的成员项，部分与本实验相关的成员项有：（相关含义自行查阅资料学习）"
                    }
                ]
            },
            "bbox": [
                144,
                827,
                848,
                860
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#define TASK_RUNNING 0 "
                    }
                ]
            },
            "bbox": [
                201,
                865,
                443,
                879
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#define TASK_INTERRUPTIBLE 1 "
                    }
                ]
            },
            "bbox": [
                203,
                883,
                443,
                898
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "define TASK_UNINTERRUPTIBLE 2\n#define _TASK_STOPPED 4\n#define _TASK tracerED 8\n/* in tsk->exit_state */\n#define EXITDead 16\n#define EXIT_ZOMBIE 32\n/* in tsk->state again */\n#define TASK_DEAD 64\n#define TASK_WAKEKILL 128\n#define TASK_WAKING 256\nstruct task_struct {\n    volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */\n    void *stack;\n    int prio, static_prio, normal_prio;\n    unsigned int policy;\n    struct list_head tasks; /*线程组长链表，是节点*/\n    struct mm_struct *mm, *active_mm;\n    pid_t pid;\n    pid_t tgid;\n    struct task_struct __rcu *real_parent; /* real parent process */\n    struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */\n    struct list_head children; /* list of my children */\n    struct list_head sibling; /* linkage in my parent's children list */\n    cptime_t utime, stime, utimescaled, stimescaled;\n    char comm[TASKCOMM_LEN]; /* executable name excluding path */\n}; "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                194,
                85,
                766,
                583
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux 的进程和轻量级进程/线程均有相应的 task_struct 结构和 PID 号，而 POSIX 要求同一组线程有统一的 PID，为此 linux 引入了 tgid（thread group identifer），tgid 实际上是线程组第一个线程的pid值，该线程称为线程组长。对于普通进程，其 pid与 tgid是相同的。此外，linux系统的进程包含一种特殊的类型——内核线程（kernel thread），完成内核的一些特定任务，并始终在核心态运行，没有用户态地址空间，其 task_struct 结构的 mm 成员项为NULL，如交换进程。"
                    }
                ]
            },
            "bbox": [
                144,
                586,
                848,
                694
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "实验内容（1）可以利用内核的线程组长链表实现，每个线程组长通过 task_struct 结构的 tasks 成员加入该链表。Linux 内核提供了宏 for_each_process()访问该链表中的每个进程："
                    }
                ]
            },
            "bbox": [
                161,
                697,
                848,
                749
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "define for_each_process(p) \\  \nfor (p = &init_task; (p = next_task(p)) != &init_task; ) "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                181,
                753,
                603,
                788
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "宏 for_each_process 定义在/include/linux/sched.h 文件中。 "
                    }
                ]
            },
            "bbox": [
                196,
                790,
                636,
                806
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "实验内容（2）需要了解 linux 进程家族的组织情况。所以的进程都是 PID 为 1 的 init进程的后代，内核在系统启动的最后阶段创建init进程，并由其完成后续启动工作。系统中的每个进程必有一个父进程，相应的，每个进程也可以拥有零个或多个子进程。父进程（task_struct 中的 parent 成员）相同的所有进程称为兄弟进程，由 task_struct 中的 sibling成员链接成父进程的 children链表，它们间的关系如图2-3所示："
                    }
                ]
            },
            "bbox": [
                161,
                808,
                850,
                898
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/c01a80ba569bbf26b8b3f732e9be35aaab91f0d1ae7fddc0b837200d4da3422f.jpg"
                },
                "image_caption": [
                    {
                        "type": "text",
                        "content": "图2-3 进程家族关系"
                    }
                ],
                "image_footnote": []
            },
            "bbox": [
                213,
                84,
                742,
                233
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "对子进程链表和兄弟进程链表的访问，都可以通过宏 list_for_each()和 list_entry()以及list_for_each_entry()来实现。对于指定的 pid，可以通过函数 pid_task()和 find_vpid()（或者find_get_pid()）配合使用找到其相应的 task_atruct 结构，位于 linux/kernel/pid.c 文件中："
                    }
                ]
            },
            "bbox": [
                161,
                271,
                848,
                325
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "struct task_struct *result = NULL;\nif (pid) {\n    struct hlist_node *first;\n    first = rcu_dereference_check(pid->tasks[type].first, rcu_read_lock_held() || lockdep_tasklist_lock_is_held());\n    if (first)\n        result = hlist_entry(first, struct task_struct, pid[(type).node);\n} return result;\n}\nstruct pid *find_vpid(int nr) {\n    return find.pid_ns(nr, current->nsproxy->pid_ns);\n}\nstruct pid *find_get.pid(pid_t nr) {\n    struct pid *pid;\n    pid = get.pid找到了pid(nr));\n    rcu_read_unlock();\n    return pid;\n} "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                194,
                346,
                702,
                750
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "实验三 linux 设备驱动程序开发"
                    }
                ],
                "level": 1
            },
            "bbox": [
                278,
                793,
                734,
                816
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3.1 设计目的和内容要求"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                848,
                470,
                869
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1．设计目的"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                95,
                285,
                110
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux驱动程序占了内核代码的一半以上，开发设计驱动程序是 linux内核编程的一项很重要的工作。通过本次实验，学习者应了解 linux 的设备管理机制及驱动程序的组织结构；掌握linux设备驱动程序的编写流程及加载方法，为从事具体的硬件设备驱动程序开发打下基础。"
                    }
                ]
            },
            "bbox": [
                144,
                123,
                848,
                193
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2．内容要求"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                206,
                285,
                222
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1） 编写一个字符设备驱动程序，要求实现对该字符设备的打开、读、写、I/O 控制和关闭5 个基本操作。为了避免牵涉到汇编语言，这个字符设备并非一个真实的字符设备，而是用一段内存空间来模拟的。以模块方式加载该驱动程序。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2） 编写一个应用程序，测试（1）中实现的驱动程序的正确性。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3） 有兴趣的同学还可以编写一个块设备的驱动程序。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）请根据自身情况，进一步阅读分析程序中用到的相关内核函数的源码实现。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                234,
                848,
                342
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3. 学时安排（共 6学时）"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                373,
                381,
                388
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4． 开发平台"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                410,
                292,
                425
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux 环境，gcc，gdb，vim 或 gedit 等。"
                    }
                ]
            },
            "bbox": [
                216,
                438,
                519,
                454
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3.2 linux 设备管理概述"
                    }
                ],
                "level": 1
            },
            "bbox": [
                173,
                480,
                448,
                500
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3.2.1 设备文件的概念"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                535,
                401,
                552
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux沿用了Unix的设备管理思想，将所有设备看成是一类特殊文件，即为每个设备建立一个设备文件，一般保存在/dev目录下，如/dev/hda1标识第一个硬盘的第一个逻辑分区。Linux将系统中的设备分成三类："
                    }
                ]
            },
            "bbox": [
                144,
                564,
                847,
                615
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "块设备：一次 I/O 操作是固定大小的数据块，可随机存取，其设备文件的属性字段中以“b”进行标识；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "字符设备：只能按字节访问的设备，一次 I/O操作存取数据量不固定，只能顺序存取，其设备文件的属性字段中以“c”进行标识；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "网络设备：网卡是特殊处理的，没有对应的设备文件。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                179,
                619,
                847,
                709
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3.2.2 设备号的概念"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                721,
                379,
                738
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1．什么是设备号"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                758,
                319,
                774
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "与普通文件一样，每个设备文件都有文件名和一个唯一的索引节点，在索引节点中记录了与特定设备建立连接所需的信息，其中最主要的三个信息是："
                    }
                ]
            },
            "bbox": [
                144,
                785,
                847,
                820
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "类型：表明是字符设备还是块设备；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "主设备号：主设备号相同的设备，由同一个驱动程序控制；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "次设备号：说明该设备是同类设备中的第几个，即表示具体的某个设备。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                179,
                824,
                769,
                875
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如查看/dev目录，可看到如下一些信息："
                    }
                ]
            },
            "bbox": [
                181,
                879,
                495,
                894
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/d24110f75720da97ed981ac4b0fa7b47e58905bf9cb7bcedd48d8bda80a93f2a.jpg"
                },
                "image_caption": [],
                "image_footnote": []
            },
            "bbox": [
                181,
                84,
                734,
                139
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "可见，sda1、sda2、sda5 是同一类块设备，它们的主设备号都是8，次设备号分别是1、2 和 5。"
                    }
                ]
            },
            "bbox": [
                144,
                141,
                836,
                174
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "由主设备号和次设备号组成了设备的唯一编号：设备号，其类型为 dev_t，是一个 32位的无符号整数，定义在/usr/src/linux-4.4.19/include/linux/types.h 文件中："
                    }
                ]
            },
            "bbox": [
                144,
                178,
                848,
                212
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "typedef __u32 __kernel_dev_t; "
                    }
                ]
            },
            "bbox": [
                179,
                216,
                413,
                231
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "typedef __kernel_dev_t dev_t; "
                    }
                ]
            },
            "bbox": [
                181,
                235,
                443,
                250
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. 与设备号相关的操作函数"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                262,
                405,
                277
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1） 定义在/usr/include/linux/kdev_t.h 中的三个宏："
                    }
                ]
            },
            "bbox": [
                188,
                290,
                596,
                305
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "#define MAJOR(dev) ((dev)>>8) //从 dev（dev_t 类型）中获得主设备号"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "#define MINOR(dev) ((dev) & 0xff) //从 dev（dev_t 类型）中获得次设备号"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "#define MKDEV(ma,mi) ((ma)<<8 | (mi)) //将主、次设备号组合成 dev_t 类型的设备号"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                216,
                307,
                847,
                379
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（2） 为字符设备静态分配设备号："
                    }
                ]
            },
            "bbox": [
                186,
                382,
                465,
                397
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如果驱动程序开发者清楚了解系统中尚未被使用的设备号，则可直接指定主设备号，然后再申请若干个连续的次设备号。这种方法可能会造成系统中设备号冲突，而使驱动程序无法注册。函数原型定义在/usr/src/linux-4.4.19/include/linux/fs.h 文件中，为："
                    }
                ]
            },
            "bbox": [
                144,
                400,
                845,
                454
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "int register_chrdev_region(dev_t first, unsigned int count, char *name); "
                    }
                ]
            },
            "bbox": [
                179,
                458,
                699,
                472
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "函数功能：为一个指定主设备号的字符驱动程序申请一个或一组连续的次设备号。"
                    }
                ]
            },
            "bbox": [
                179,
                475,
                811,
                489
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "输入参数："
                    }
                ]
            },
            "bbox": [
                181,
                494,
                263,
                508
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "first ：dev_t 类型的起始设备号（可通过 MKDEV(major,0)获得）；"
                    }
                ]
            },
            "bbox": [
                179,
                512,
                670,
                527
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "count：需要申请的次设备号数量；"
                    }
                ]
            },
            "bbox": [
                179,
                531,
                445,
                546
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "name：设备名，会出现在 /proc/devices 和 sysfs 中；"
                    }
                ]
            },
            "bbox": [
                179,
                550,
                594,
                565
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "返回值：分配成功返回0，失败返回一个负的错误码"
                    }
                ]
            },
            "bbox": [
                179,
                568,
                589,
                582
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（3） 为字符设备动态分配设备号："
                    }
                ]
            },
            "bbox": [
                186,
                586,
                465,
                601
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如果没有提前指定主设备号，则采用动态申请方式，它不会出现设备号冲突的问题，但是无法在安装驱动前创建设备文件（因为安装前还没有分配到主设备号）。"
                    }
                ]
            },
            "bbox": [
                144,
                605,
                833,
                638
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "函数原型定义在/usr/src/linux-4.4.19/include/linux/fs.h 文件中："
                    }
                ]
            },
            "bbox": [
                179,
                642,
                653,
                657
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "int alloc_chrdev_region(dev_t *dev,unsigned firstminor,unsigned count,char *name)； "
                    }
                ]
            },
            "bbox": [
                179,
                661,
                794,
                676
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "函数功能：动态分配一个主设备号及一个或一组连续次设备号。"
                    }
                ]
            },
            "bbox": [
                179,
                678,
                670,
                694
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "输入参数："
                    }
                ]
            },
            "bbox": [
                181,
                697,
                263,
                712
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "firstminor：起始次设备号，一般从 0 开始；"
                    }
                ]
            },
            "bbox": [
                179,
                715,
                510,
                731
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "count：需要分配的次设备号数量；"
                    }
                ]
            },
            "bbox": [
                179,
                734,
                445,
                749
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "name：设备名，会出现在 /proc/devices 和 sysfs 中；"
                    }
                ]
            },
            "bbox": [
                179,
                753,
                594,
                768
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "输出参数：系统自动分配的 dev_t类型的设备号；"
                    }
                ]
            },
            "bbox": [
                179,
                772,
                559,
                785
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "返回值：分配成功返回0，失败返回一个负的错误码。"
                    }
                ]
            },
            "bbox": [
                179,
                790,
                594,
                804
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（4） 释放设备号："
                    }
                ]
            },
            "bbox": [
                188,
                809,
                339,
                824
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "采用上面两种方式申请到的设备号，在设备不使用时，比如在调用cdev_del()函数从系统中注销字符设备之后，应该及时释放掉。释放设备号使用的函数原型定义在/usr/src/linux-4.4.19/include/linux/fs.h 文件中："
                    }
                ]
            },
            "bbox": [
                144,
                827,
                845,
                879
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "void unregister_chrdev_region(dev_t from, unsigned count); "
                    }
                ]
            },
            "bbox": [
                213,
                883,
                653,
                898
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "其中参数含义跟上面（2）中的一样。"
                    }
                ]
            },
            "bbox": [
                179,
                85,
                465,
                101
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（5） 查看设备号使用情况："
                    }
                ],
                "level": 1
            },
            "bbox": [
                188,
                105,
                410,
                118
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "当静态分配设备号时，需要查看系统中已经使用掉的设备号，从而决定使用哪个新设备号。可使用命令“cat /proc/devices”查看，显示的字符设备的最后一行信息如下所示："
                    }
                ]
            },
            "bbox": [
                144,
                122,
                848,
                156
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Character devices: "
                    }
                ]
            },
            "bbox": [
                181,
                161,
                332,
                174
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "254 mdp "
                    }
                ]
            },
            "bbox": [
                200,
                180,
                309,
                193
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "则新添加设备驱动时可以选择主设备号255。"
                    }
                ]
            },
            "bbox": [
                181,
                197,
                524,
                212
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3.2.3 字符设备管理相关数据结构"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                224,
                500,
                241
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. struct cdev 结构"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                262,
                352,
                275
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "Linux内核中使用structcdev来描述一个字符设备，定义在/usr/src/linux-4.4.19/  \ninclude/linux/cdev.h文件中：struct cdev{struct kobject kobj; /*内嵌的内核对象，包括引用计数、名称、父指针等*/struct module \\*owner; /*所属内核模块，一般设置为THISMODULE*/const struct file_operations \\*ops; /*设备操作集合\\*/struct list_head list; /*设备的inode链表头\\*/dev_t dev; /*设备号\\*/unsigned int count; /*分配的设备号数目\\*/}；"
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                161,
                288,
                833,
                470
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "cdev 结构是内核对字符设备的标准描述，在实际的设备驱动开发中，通常使用自定义的结构体来描述一个特定的字符设备：内嵌 cdev 结构，同时包含其他描述该具体设备特性的字段。比如本实验中，用一段内存来模拟字符设备："
                    }
                ]
            },
            "bbox": [
                144,
                475,
                848,
                527
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "struct mymem_dev\n{\n    Struct cdev cdev;\n    Unsigned char mem[512];\n}; "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                196,
                532,
                408,
                620
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. struct char_device_struct 结构"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                633,
                473,
                648
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "内核为主设备号相同的一组设备设置一个 char_device_struct 结构，描述这个主设备号下已经被分配的次设备号区间："
                    }
                ]
            },
            "bbox": [
                144,
                659,
                848,
                694
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "static struct char_device_struct{ struct char_device_struct \\*next; /*指向散列链表中的下一个元素的指针*/ unsigned int major; /\\*主设备号\\*/ unsigned int baseminor; /\\*起始次设备号\\*/ int minorct; /\\*次设备号区间大小\\*/ char name[64]; /\\*设备名\\*/ struct file_operations \\*fops; /\\*未使用\\*/ struct cdev \\*cdev; /\\*指向字符设备描述符的指针\\*/   \n\\*chrdevs[CHRDEV Major HASH SIZE];"
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                200,
                697,
                821,
                862
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3. file_operations 结构"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                873,
                381,
                889
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "file_operations 结构体是字符设备中最重要的数据结构之一。其中的成员是一组函数指针，用于实现相应的系统调用，如 open()、read()、write()、close()、seek()、ioctl()等系统调用最终就是这组函数实现的，是字符设备驱动程序设计的主体内容。"
                    }
                ]
            },
            "bbox": [
                144,
                85,
                848,
                137
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "file_operations 结构体中对字符设备比较重要的成员主要有："
                    }
                ]
            },
            "bbox": [
                179,
                141,
                640,
                156
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "struct file_operations{ struct module \\*owner; /*拥有该结构的模块，一般为THIS_MODULE*/ ssize_t (*read) (struct file \\*, char __user \\*, size_t, loff_t \\*); /*从设备中读取数据*/ ssize_t (\\*write) (struct file \\*, const char __user \\*, size_t, loff_t \\*);/*向设备中写数据*/ int (\\*ioctl) (struct inode \\*, struct file \\*, unsigned int, unsigned long); /*执行设备的I/O 控制命令\\*/ int (\\*open) (struct inode \\*, struct file \\*); /*打开设备文件\\*/ int (\\*release) (struct inode \\*, struct file \\*); /*关闭设备文件\\*/ "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                181,
                161,
                850,
                342
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4. file 结构"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                373,
                280,
                387
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "file 结构代表一个打开的文件，内核每执行一次 open操作就会建立一个file 结构，因此一个文件可以对应多个 file 结构。其中几个重要的成员有："
                    }
                ]
            },
            "bbox": [
                144,
                400,
                848,
                434
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "struct file{\nmode_t fmode; /*文件模式，如FMODE_READ，FMODE_WRITE*/\nloff_t f_pos; /*当前读写指针*/\nstruct file_operations *f_op; /*文件操作函数表指针*/\nvoid *private_data; /*非常重要，用于存放转换后的设备描述结构指针*/\n};"
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                179,
                439,
                747,
                565
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5. inode 结构"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                577,
                305,
                590
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "磁盘上每个文件都有一个 inode，对于设备文件来说，有两个很重要的成员："
                    }
                ]
            },
            "bbox": [
                179,
                604,
                766,
                621
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "struct inode {\n    dev_t i_rdev; /*设备号*/\n    struct cdev *i_cdev; /*该设备的 cdev 结构*/\n        ......\n};"
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                181,
                625,
                574,
                712
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "根据其设备号可以得到其主设备号和次设备号。"
                    }
                ]
            },
            "bbox": [
                179,
                715,
                544,
                730
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3.3 linux 字符设备驱动程序的设计"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                777,
                584,
                796
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3.3.1 linux 字符设备驱动程序框架"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                832,
                515,
                848
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux字符设备驱动程序框架如图 3-1所示："
                    }
                ]
            },
            "bbox": [
                179,
                860,
                522,
                876
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/094cf3a8258652b6f4357299f1d4d3141e1b739b8b0535754fb786d20832020a.jpg"
                },
                "image_caption": [
                    {
                        "type": "text",
                        "content": "图3-1 字符设备驱动程序框架图"
                    }
                ],
                "image_footnote": []
            },
            "bbox": [
                183,
                84,
                788,
                361
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3.3.2 linux 字符设备驱动程序中需要的一组头文件"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                391,
                658,
                407
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在编写 linux 字符设备驱动程序时，可能要用到的头文件包括："
                    }
                ]
            },
            "bbox": [
                179,
                419,
                668,
                435
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#include <linux/fs.h> //定义文件表结构（file 结构,buffer_head,m_inode 等）"
                    }
                ]
            },
            "bbox": [
                203,
                438,
                800,
                454
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#include <linux/types.h> //对一些特殊的系统数据类型的定义，例如 dev_t, off_t,pid_t.其实这些类型大部分都是 unsigned int 型通过一连串的 typedef 变过来的，只是为了方便阅读。"
                    }
                ]
            },
            "bbox": [
                203,
                456,
                848,
                508
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#include <linux/cdev.h> //包含了 cdev 结构及相关函数的定义。"
                    }
                ]
            },
            "bbox": [
                203,
                512,
                705,
                527
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#include <asm/uaccess.h> //包含 copy_to_user(),copy_from_user()的定义 "
                    }
                ]
            },
            "bbox": [
                203,
                531,
                764,
                546
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#include <linux/module> //模块编程相关函数"
                    }
                ]
            },
            "bbox": [
                203,
                549,
                563,
                564
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#Include <linux/init.h> //模块编程相关函数"
                    }
                ]
            },
            "bbox": [
                203,
                568,
                554,
                583
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#include <linux/kernel> "
                    }
                ]
            },
            "bbox": [
                205,
                587,
                379,
                601
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#include <linux/slab.h> //包含内核的内存分配相关函数，如 kmalloc()/kfree()等"
                    }
                ]
            },
            "bbox": [
                203,
                605,
                811,
                621
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3.3.3 字符设备驱动程序的初始化"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                632,
                495,
                646
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. 分配设备号"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                670,
                307,
                684
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如3.2.2 节所述，为一个新字符设备分配设备号可以有静态和动态两种方式，如果提前指定主设备号，则使用静态方式："
                    }
                ]
            },
            "bbox": [
                144,
                697,
                845,
                731
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "int register_chrdev_region(dev_t first, unsigned int count, char *name); "
                    }
                ]
            },
            "bbox": [
                147,
                734,
                699,
                751
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "否则使用动态分配方式："
                    }
                ]
            },
            "bbox": [
                147,
                753,
                334,
                768
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "int alloc_chrdev_region(dev_t *dev,unsigned firstminor,unsigned count,char *name)； "
                    }
                ]
            },
            "bbox": [
                178,
                772,
                794,
                788
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. 定义 cdev 结构并初始化"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                800,
                410,
                814
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "linux内核必须为每个字符设备都建立一个 cdev结构，定义时采用cdev 结构体指针或变量均可，只不过两种定义方式的初始化操作会有所不同："
                    }
                ]
            },
            "bbox": [
                144,
                827,
                848,
                860
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1） 定义 cdev 结构体及初始化："
                    }
                ]
            },
            "bbox": [
                188,
                865,
                453,
                879
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "struct cdev my_cdev; "
                    }
                ]
            },
            "bbox": [
                240,
                884,
                396,
                898
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "cdev_init(&my_cdev, &fops);  \nmy_cdev owner = THISMODULE; "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                240,
                86,
                489,
                120
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（2） 定义 cdev 结构指针及初始化："
                    }
                ]
            },
            "bbox": [
                189,
                123,
                472,
                137
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "struct cdev *my_cdev = cdev_alloc();\nmy_cdev->ops = &fops;\nmy_cdev->owner = THISMODULE; "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                240,
                142,
                509,
                193
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "其实，cdev_init()和cdev_alloc()的功能是差不多的，只是前者多了一个ops的赋值操作，具体区别参看下面两个函数的实现代码："
                    }
                ]
            },
            "bbox": [
                144,
                197,
                836,
                230
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "struct cdev *cdev_alloc(void)  \n{  \n    struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);  \n    if (p) {  \n        INIT_LIST_HEAD(&p->list);  \n        kobject_init(&p->kobj, &ktype_cdev_dynamic);  \n    }  \n    return p;  \n}  \nvoid cdev_init(struct cdev *cdev, const struct file_operations *fops)  \n{  \n    memset(cdev, 0, sizeof *cdev);  \n    INIT_LIST_HEAD(&cdev->list);  \n    kobject_init(&cdev->kobj, &ktype_cdev_default);  \n    cdev->ops = fops; "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                205,
                233,
                695,
                545
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "两个函数的原型定义在/usr/src/linux-4.4.19/include/linux/cdev.h 文件中。"
                    }
                ]
            },
            "bbox": [
                206,
                549,
                751,
                564
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3. 注册 cdev 结构"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                577,
                339,
                592
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "cdev 初始化完成后，应将其注册到系统中，一般在模块加载时完成该操作。设备注册函数是 cdev_add()，其原型定义在/usr/src/linux-4.4.19/include/linux/cdev.h 文件中："
                    }
                ]
            },
            "bbox": [
                144,
                605,
                847,
                639
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "int cdev_add(struct cdev *p, dev_t dev, unsigned count)  \n{  \n    p->dev = dev;  \n    p->count = count;  \n    return kobj_map(cdev_map, dev, count, NULL, exact_MATCH, exact_lock, p);  \n} "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                179,
                642,
                818,
                750
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "其中的输入参数分别是 cdev 结构指针、起始设备号、次设备号数量"
                    }
                ]
            },
            "bbox": [
                181,
                753,
                705,
                768
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "linux 内核中所有字符设备都记录在一个 kobj_map 结构的 cdev_map 散列表里。cdev_add() 函 数 中 的 kobj_map() 函 数 就 是 用 来 把 设 备 号 及 cdev 结 构 一 起 保 存 到cdev_map 散列表里。当以后要打开这个字符设备文件时，通过调用 kobj_lookup() 函数，根据设备号就可以找到 cdev 结构变量，从而取出其中的 ops 字段。"
                    }
                ]
            },
            "bbox": [
                144,
                771,
                845,
                843
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "执行 cdev_add()操作后，意味着一个字符设备对象已经加入了系统，以后用户程序可以通过文件系统接口找到对应的驱动程序。"
                    }
                ]
            },
            "bbox": [
                144,
                846,
                845,
                879
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3.3.4 实现字符设备驱动程序的操作函数"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                891,
                556,
                908
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. 实现 file_operations 结构中要用到的函数"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                95,
                549,
                111
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "这些函数具体实现设备的相关操作，如打开设备、读设备等，部分函数的大致结构可参看下面的描述："
                    }
                ]
            },
            "bbox": [
                144,
                123,
                845,
                156
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1） 打开设备函数 open："
                    }
                ]
            },
            "bbox": [
                189,
                160,
                400,
                175
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "static int char_dev_open(struct inode *inode, struct file *filp)  \n{ // 这里可以进行一些初始化  \n    printf(\"char_dev_device_open.\\n\");  \n    return 0;  \n}"
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                240,
                179,
                680,
                287
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（2） 读设备函数"
                    }
                ]
            },
            "bbox": [
                189,
                290,
                337,
                305
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "ssize_t char_dev_read(struct file *file, char __user *buff, size_t count,loff_t *offp) {\n    ...\n    copy_to_user();\n    ...\n} "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                240,
                309,
                823,
                417
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（3） 写设备函数"
                    }
                ]
            },
            "bbox": [
                189,
                420,
                337,
                435
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "ssize_t char_dev_write(struct file *file, const char __user *buff, size_t count,loff_t *offp)  \n{  \n    ...  \n    copy_from_user();  \n    ...  \n} "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                240,
                439,
                845,
                565
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（4） I/O控制函数"
                    }
                ]
            },
            "bbox": [
                189,
                567,
                349,
                583
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "static int char_dev_ioctl(struct inode *inode,struct file *filp,unsigned int cmd, unsigned long arg)   \n{ ... switch(cmd) { case xxx_cmd1: break; case xxx_cmd2: break; ... } "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                240,
                587,
                796,
                843
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（5） 关闭设备函数 release，对应用户空间的 close 系统调用"
                    }
                ]
            },
            "bbox": [
                189,
                846,
                675,
                860
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "static int char_dev_release(struct inode *node, struct file *file) { "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                240,
                865,
                694,
                898
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "//这里可以进行一些资源的释放printk(\"char_devdevice release.\\n\");return0;"
                    }
                ],
                "code_language": "javascript"
            },
            "bbox": [
                240,
                85,
                524,
                156
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. 添加 file_operations 成员"
                    }
                ],
                "level": 1
            },
            "bbox": [
                184,
                168,
                421,
                185
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "file_operations结构体中包含很多函数指针，是驱动程序与内核的接口，下面列出最常用的几种操作："
                    }
                ]
            },
            "bbox": [
                147,
                196,
                845,
                230
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "static struct file_operations char_dev_fops =  \n{  \n    .owner = THISMODULE,  \n    .open = char_dev_open, //打开设备  \n    .release = char_dev_release, //关闭设备  \n    .read = char_dev_read, //实现设备读功能  \n    .write = char_dev_write, //实现设备写功能  \n    .ioct1 = char_dev_ioct1, //实现设备控制功能  \n}; "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                181,
                235,
                554,
                398
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3.3.5 注销设备"
                    }
                ],
                "level": 1
            },
            "bbox": [
                193,
                410,
                332,
                425
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "当不使用某个设备时，应及时从系统注销，以节省系统资源。注销设备主要包括两个操作：撤销cdev结构和释放设备号，此项工作通常放在模块卸载过程中完成。"
                    }
                ]
            },
            "bbox": [
                147,
                437,
                848,
                472
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. 撤销 cdev 结构"
                    }
                ],
                "level": 1
            },
            "bbox": [
                184,
                483,
                337,
                499
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "Linux内核使用cdev_del()函数向系统删除一个cdev，完成字符设备的注销：  \nvoid cdev_del(struct cdev *p)  \n{  \n    cdev_unmap(p->dev, p->count); //调用 kobj_unmap()释放 cdev_map散列表中的对象  \n    kobj_put(&p->kobj); //释放 cdev结构本身  \n}"
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                181,
                511,
                840,
                621
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. 释放设备号"
                    }
                ],
                "level": 1
            },
            "bbox": [
                184,
                651,
                305,
                665
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "调用cdev_del()函数从系统注销字符设备之后，应调用unregister_chrdev_region()释放原先申请的设备号，其函数原型为："
                    }
                ]
            },
            "bbox": [
                147,
                678,
                847,
                712
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "void unregister_chrdev_region(dev_t first, unsigned int count); "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                183,
                717,
                638,
                732
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3.4 linux 字符设备驱动程序的编译及加载"
                    }
                ],
                "level": 1
            },
            "bbox": [
                194,
                758,
                655,
                778
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "当以模块方式实现一个字符设备的驱动程序后，可从按以下步骤对驱动程序进行编译和加载："
                    }
                ]
            },
            "bbox": [
                147,
                804,
                847,
                838
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. 编译模块"
                    }
                ],
                "level": 1
            },
            "bbox": [
                184,
                851,
                287,
                866
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在驱动程序源码文件所在目录中建立Makefile文件，参考内容如下："
                    }
                ]
            },
            "bbox": [
                189,
                879,
                705,
                894
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "obj-m :=c_driver.o "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                183,
                898,
                317,
                913
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "KDIR :=/usr/src/linux-headers-4.4.0-36-generic  \nPWD :=$(shell pwd)  \ndefault:  \n    make -C $(KDIR) M=$(PWD) modules  \nclean:  \n    make -C $(KDIR) M=$(PWD) clean"
                    }
                ],
                "code_language": "makefile"
            },
            "bbox": [
                181,
                86,
                557,
                193
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "然后使用make命令编译模块，得到.ko文件。"
                    }
                ]
            },
            "bbox": [
                181,
                197,
                524,
                212
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. 使用 insmod 命令加载模块（需要 root 权限）"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                225,
                571,
                240
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "加载后可使用“cat /proc/devices”查看所加载的设备"
                    }
                ]
            },
            "bbox": [
                179,
                252,
                591,
                268
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3. 建立设备节点（即设备文件）"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                280,
                440,
                296
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "根据设备号在文件系统中建立对应的设备节点（即设备文件），使用命令 mknod，如：#mknod /dev/mycdev c 145 0"
                    }
                ]
            },
            "bbox": [
                200,
                307,
                838,
                341
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "从而建立了/dev/mycdev 文件与（145,0）号设备的连接"
                    }
                ]
            },
            "bbox": [
                181,
                344,
                608,
                361
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4. 可根据需要修改设备文件的权限"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                373,
                465,
                388
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如：#chmod 777 /dev/mycdev "
                    }
                ]
            },
            "bbox": [
                201,
                401,
                457,
                416
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "至此，一个新设备建立完毕，以后应用程序就可以使用文件操作函数如“open”等操作/dev/mycdev 设备了。"
                    }
                ]
            },
            "bbox": [
                208,
                419,
                847,
                454
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "实验四 linux 进程管理"
                    }
                ],
                "level": 1
            },
            "bbox": [
                299,
                495,
                631,
                521
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4.1 设计目的和内容要求"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                552,
                458,
                571
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. 设计目的"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                608,
                282,
                623
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）熟悉linux的命令接口。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）通过对linux 进程控制的相关系统调用的编程应用，进一步加深对进程概念的理解，明确进程和程序的联系和区别，理解进程并发执行的具体含义。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）通过 Linux 管道通信机制、消息队列通信机制、共享内存通信机制的使用，加深对不同类型的进程通信方式的理解。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）通过对linux的Posix 信号量的应用，加深对信号量同步机制的理解。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）请根据自身情况，进一步阅读分析相关系统调用的内核源码实现。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                636,
                848,
                762
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. 设计内容"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                775,
                282,
                790
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1）熟悉 linux 常用命令：pwd，useradd，passwd, who, ps, pstree, kill, top, ls, cd, mkdir,rmdir, cp, rm, mv, cat, more, grep 等。"
                    }
                ]
            },
            "bbox": [
                144,
                804,
                848,
                837
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（2） 实现一个模拟的 shell："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                840,
                408,
                854
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "编写三个不同的程序 cmd1.c，cmd2.c，cmd3.c，每个程序的功能自定，分别编译成可执行文件 cmd1，cmd2，cmd3。然后再编写一个程序，模拟 shell 程序的功能，能根据用户输入的字符串（表示相应的命令名），去为相应的命令创建子进程并让它去执行相应的程序，"
                    }
                ]
            },
            "bbox": [
                144,
                859,
                848,
                910
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "而父进程则等待子进程结束，然后再等待接收下一条命令。如果接收到的命令为exit，则父进程结束；如果接收到的命令是无效命令，则显示“Command not found”，继续等待。"
                    }
                ]
            },
            "bbox": [
                144,
                85,
                850,
                120
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（3） 实现一个管道通信程序："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                123,
                423,
                137
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "由父进程创建一个管道，然后再创建 3个子进程，并由这三个子进程利用管道与父进程之间进行通信：子进程发送信息，父进程等三个子进程全部发完消息后再接收信息。通信的具体内容可根据自己的需要随意设计，要求能试验阻塞型读写过程中的各种情况，测试管道的默认大小，并且要求利用 Posix信号量机制实现进程间对管道的互斥访问。运行程序，观察各种情况下，进程实际读写的字节数以及进程阻塞唤醒的情况。"
                    }
                ]
            },
            "bbox": [
                144,
                141,
                852,
                231
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（4）利用 linux 的消息队列通信机制实现两个线程间的通信："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                234,
                653,
                249
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "编写程序创建两个线程：sender 线程和 receive 线程，其中 sender 线程运行函数 sender()，它创建一个消息队列，然后，循环等待用户通过终端输入一串字符，将这串字符通过消息队列发送给receiver 线程，直到用户输入“exit”为止；最后，它向 receiver 线程发送消息“end”，并且等待 receiver 的应答，等到应答消息后，将接收到的应答信息显示在终端屏幕上，删除相关消息队列，结束程序的运行。Receiver 线程运行 receive()，它通过消息队列接收来自sender的消息，将消息显示在终端屏幕上，直至收到内容为“end”的消息为止，此时，它向 sender 发送一个应答消息“over”，结束程序的运行。使用无名信号量实现两个线程之间的同步与互斥。"
                    }
                ]
            },
            "bbox": [
                144,
                252,
                852,
                398
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（5）利用 linux的共享内存通信机制实现两个进程间的通信："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                401,
                653,
                416
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "编写程序sender，它创建一个共享内存，然后等待用户通过终端输入一串字符，并将这串字符通过共享内存发送给 receiver；最后，它等待 receiver 的应答，收到应答消息后，将接收到的应答信息显示在终端屏幕上，删除共享内存，结束程序的运行。编写receiver 程序，它通过共享内存接收来自 sender 的消息，将消息显示在终端屏幕上，然后再通过该共享内存向sender发送一个应答消息“over”，结束程序的运行。使用有名信号量或 System V 信号量实现两个进程对共享内存的互斥及同步使用。"
                    }
                ]
            },
            "bbox": [
                144,
                419,
                850,
                527
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3. 学时安排（共 6学时）"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                539,
                379,
                555
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4．开发平台"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                577,
                284,
                592
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux 环境，gcc，gdb，vim 或 gedit 等。"
                    }
                ]
            },
            "bbox": [
                216,
                605,
                519,
                621
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5. 思考"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                633,
                245,
                646
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）OS向用户提供的命令接口、图形接口和程序接口分别适用于哪些场合？"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）系统调用和用户自己编制的子函数有什么区别？通常操作系统提供的 API与系统调用有什么联系和区别？"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）进程和程序有何联系，又有哪些区别？"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）一个进程从出生到终止，其状态会经历哪些变化？"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）用户可如何取得进程的控制信息？"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（6）当首次将CPU调度给子进程时，它将从哪里开始执行指令？"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（7）虽然父子进程可以完全并发执行，但在 Linux中，创建子进程成功之后，通常让子进程优先获得CPU，这种做法有什么好处？"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（8）僵尸进程通常是如何形成的？"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（9）对一个应用，如果用多个进程的并发执行来实现，与单个进程来实现有什么不同？"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（10）有名管道和无名管道之间有什么不同？"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（11）管道的读写与文件的读写有什么异同？"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                659,
                848,
                897
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（12）Linux消息队列通信机制中与教材中的消息缓冲队列通信机制存在哪些异同？"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（13）linux 中 posix 信号量与 System V 信号量有什么区别？"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                179,
                85,
                811,
                120
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4.2 Linux 基本使用："
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                165,
                426,
                185
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4.2.1 常用命令"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                219,
                332,
                236
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "pwd, passwd, who, ps, pstree, kill, top, ls, cd, mkdir, rmdir, cp, rm, mv, cat, more, grep 等。自行查阅相关资料学习。"
                    }
                ]
            },
            "bbox": [
                147,
                250,
                833,
                282
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4.2.2 Linux 的在线帮助 man"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                294,
                450,
                311
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux提供了丰富的帮助手册，当你需要查看某个命令的参数时不必到处上网查找，只要 man（man 为 manual 的简写）一下即可。"
                    }
                ]
            },
            "bbox": [
                144,
                323,
                843,
                356
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. 简单范例"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                369,
                287,
                384
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "例如，如果你不清楚 pwd 命令的用法，你可以在命令提示符下直接输入命令：man pwd，马上就会有pwd的详细资料提供给你："
                    }
                ]
            },
            "bbox": [
                146,
                397,
                836,
                431
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "PWD（1）"
                    }
                ]
            },
            "bbox": [
                181,
                434,
                265,
                449
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "User commands "
                    }
                ]
            },
            "bbox": [
                401,
                435,
                542,
                449
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Date(1)"
                    }
                ]
            },
            "bbox": [
                663,
                435,
                727,
                450
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "NAME "
                    }
                ]
            },
            "bbox": [
                181,
                453,
                240,
                466
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "pwd - print name of current/working directory "
                    }
                ]
            },
            "bbox": [
                181,
                472,
                584,
                487
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "SYNOPSIS "
                    }
                ]
            },
            "bbox": [
                181,
                489,
                277,
                504
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "pwd [OPTION] "
                    }
                ]
            },
            "bbox": [
                181,
                508,
                290,
                523
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "DESCRIPTION "
                    }
                ]
            },
            "bbox": [
                181,
                527,
                307,
                541
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "NOTE: your shell may have its own version of pwd which will supercede the version described here. Please refer to your shell's documentation for details about the options it supports. "
                    }
                ]
            },
            "bbox": [
                144,
                546,
                848,
                598
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Print the full filename of the current working directory. "
                    }
                ]
            },
            "bbox": [
                179,
                602,
                684,
                615
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "--help "
                    }
                ]
            },
            "bbox": [
                176,
                621,
                218,
                633
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "display this help and exit "
                    }
                ]
            },
            "bbox": [
                179,
                639,
                413,
                653
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "--version "
                    }
                ]
            },
            "bbox": [
                176,
                659,
                236,
                670
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "output version information and exit "
                    }
                ]
            },
            "bbox": [
                179,
                676,
                495,
                689
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "AUTHOR "
                    }
                ]
            },
            "bbox": [
                181,
                694,
                262,
                707
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Written by Jim Meyering. "
                    }
                ]
            },
            "bbox": [
                179,
                713,
                393,
                727
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "REPORTING BUGS "
                    }
                ]
            },
            "bbox": [
                181,
                731,
                347,
                745
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Report bugs to <bug-coreutils@gnu.org>. "
                    }
                ]
            },
            "bbox": [
                179,
                750,
                526,
                764
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "COPYRIGHT"
                    }
                ]
            },
            "bbox": [
                181,
                768,
                292,
                781
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Copyright "
                    },
                    {
                        "type": "equation_inline",
                        "content": "©"
                    },
                    {
                        "type": "text",
                        "content": "2004 Free Software Foundation, Inc. "
                    }
                ]
            },
            "bbox": [
                179,
                787,
                596,
                802
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. "
                    }
                ]
            },
            "bbox": [
                144,
                804,
                847,
                838
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "SEE ALSO "
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                843,
                275,
                856
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "The full documentation for pwd is maintained as a Texinfo manual. If the info and pwd programs are properly installed at your site, the command "
                    }
                ]
            },
            "bbox": [
                144,
                860,
                848,
                894
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "info coreutils pwd "
                    }
                ]
            },
            "bbox": [
                181,
                898,
                346,
                912
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "should give you access to the complete manual. "
                    }
                ]
            },
            "bbox": [
                181,
                87,
                586,
                101
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. man page 说明"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                131,
                344,
                148
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "前面的范例中，第一行名字后的数字："
                    }
                ]
            },
            "bbox": [
                181,
                160,
                473,
                175
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "\"1\"表示用户命令"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "\"2\"表示系统调用"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "\"3\"表示C语言库函数"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "\"4\"表示设备或特殊文件"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "\"5\"表示文件格式和规则"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "\"6\"表示游戏及其他"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "\"7\"表示宏、包及其他杂项"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "\"8\"表示系统管理员相关的命令"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                181,
                179,
                420,
                323
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "可见，man不仅可以查询命令，还可以查询系统调用、C语言库函数、配置文件的格式、系统管理员可用的管理命令等。值得注意的是man是按照手册的章节号的顺序进行搜索的，比如："
                    }
                ]
            },
            "bbox": [
                144,
                344,
                845,
                395
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "man sleep "
                    }
                ]
            },
            "bbox": [
                189,
                403,
                268,
                416
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "只会显示 sleep 命令的手册，如果想查看库函数 sleep，就要输入使用 man 3 sleep。"
                    }
                ]
            },
            "bbox": [
                181,
                420,
                813,
                435
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "若想知道 sleep 系统调用需要哪些头文件，则要输入 man 2 sleep"
                    }
                ]
            },
            "bbox": [
                181,
                439,
                677,
                454
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "通常，man page 大致分几个部分："
                    }
                ]
            },
            "bbox": [
                181,
                475,
                443,
                491
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "NAME 简短的命令、数据名称说明"
                    }
                ]
            },
            "bbox": [
                181,
                494,
                539,
                508
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "SYNOPSIS 简短的命令语法简介"
                    }
                ]
            },
            "bbox": [
                181,
                513,
                475,
                527
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "DESCRIPTION 较为完整的说明，这部分最好仔细看看、"
                    }
                ]
            },
            "bbox": [
                181,
                531,
                616,
                546
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "OPTIONS 针对 SYNOPSIS部分中，列举说明所有可用的参数"
                    }
                ]
            },
            "bbox": [
                181,
                549,
                690,
                564
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "COMMANDS 当这个程序（软件）在执行的时候，可以在此程序（软件）中发出的命令"
                    }
                ]
            },
            "bbox": [
                146,
                568,
                842,
                601
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "FILES 这个程序或数据所使用、参考或连接的某些参考说明"
                    }
                ]
            },
            "bbox": [
                181,
                605,
                715,
                620
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "SEE ALSO 与这个命令或数据相关的其他参考说明、"
                    }
                ]
            },
            "bbox": [
                181,
                624,
                621,
                638
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EXAMPLE 一些可以参考的范例"
                    }
                ]
            },
            "bbox": [
                181,
                642,
                473,
                657
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "BUGS 是否有相关的错误"
                    }
                ]
            },
            "bbox": [
                181,
                661,
                473,
                675
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3. man page 中可以使用的常用按键"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                707,
                480,
                722
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在man中的按键使用："
                    }
                ]
            },
            "bbox": [
                181,
                734,
                356,
                749
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "空格键 向下翻一页"
                    }
                ]
            },
            "bbox": [
                181,
                753,
                413,
                768
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "[Page Down] 向下翻一页 "
                    }
                ]
            },
            "bbox": [
                181,
                772,
                408,
                787
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "[Page Up] 向上翻一页 "
                    }
                ]
            },
            "bbox": [
                181,
                791,
                405,
                806
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "[Home] 到第一页"
                    }
                ]
            },
            "bbox": [
                181,
                810,
                389,
                824
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "[End] 到最后一页"
                    }
                ]
            },
            "bbox": [
                181,
                828,
                400,
                843
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "/word 向下搜索 word 字符串，如果要搜索 date 的话，就输入/date"
                    }
                ]
            },
            "bbox": [
                181,
                846,
                769,
                860
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "?word 向上搜索word字符串 "
                    }
                ]
            },
            "bbox": [
                181,
                865,
                478,
                879
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "n,N 使用/或?来搜索字符串时，可以用n来继续下一个搜索（不论是/还是?），"
                    }
                ]
            },
            "bbox": [
                181,
                883,
                843,
                898
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "可以使用N 来进行“反向”搜索。"
                    }
                ]
            },
            "bbox": [
                287,
                85,
                529,
                101
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "举例来说，我以/date 搜索 date 字符串，那么可以用 n继续往下查询，用 N 往上查询。若以?date 向上查询date字符串，可以用n继续 “向上”查询，用N反向查询"
                    }
                ]
            },
            "bbox": [
                144,
                104,
                847,
                139
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "q 结束并退出 man page"
                    }
                ]
            },
            "bbox": [
                181,
                142,
                440,
                156
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4. 互联网上的在线 Linux man 手册"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                168,
                473,
                184
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "即使不在 Linux 下，也可以通过某些网站在线查询某个 Linux 的命令，如："
                    }
                ]
            },
            "bbox": [
                179,
                197,
                746,
                212
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "http://www.linuxmanpages.com/ "
                    }
                ]
            },
            "bbox": [
                203,
                216,
                452,
                231
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在这里有非常全的 Linux 的 man 信息，你可以分 1－8 来查看相应的 manual 。"
                    }
                ]
            },
            "bbox": [
                179,
                234,
                781,
                249
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4.2.3 vi 和 vim 编辑器"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                262,
                415,
                277
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. vi 和 vim 简介"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                299,
                329,
                313
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在计算机系统中，编辑文本文件是用户经常要进行的操作。所谓文本文件指的是由ASCII码字符构成的文件。vi 编辑器是 Unix/Linux 系统提供的文本编辑器，用于创建和修改文本文件。vi 编辑器与其他字处理软件不同，它不包含任何格式方面的信息，如粗体、居中或者下划线等。"
                    }
                ]
            },
            "bbox": [
                144,
                326,
                850,
                398
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "vi编辑器是一个全屏幕编辑器，用户可以在整个文档范围内自由移动光标进行编辑操作。vi编辑器中有100多个命令可供用户使用，提供了丰富的编辑功能，当然对于学习使用者来说也是个挑战。但是不必灰心，因为只有少数一些命令是必须使用，或者使用频繁的，所以只要熟练掌握这些常用命令就可以完成大部分文本文件的编辑任务了。"
                    }
                ]
            },
            "bbox": [
                144,
                401,
                853,
                470
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "vim 可以当做 vi 的升级版，vi 的命令几乎都可以在 vim 上使用。Vim 会依据文件扩展名或文件的开头信息来判断文件内容，而自动执行该程序的语法判断，再以颜色来显示程序代码和一般信息。因此 vim用于程序编辑更加方便。"
                    }
                ]
            },
            "bbox": [
                144,
                475,
                850,
                527
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在系统提示符（$、#）下，输入：vi <文件名>，vi可以自动载入所要编辑的文件或创建一个新文件（若该文件不存在）。"
                    }
                ]
            },
            "bbox": [
                144,
                530,
                850,
                565
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. vi 的三种工作模式"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                577,
                361,
                592
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "vi编辑器有三种工作模式：一般模式、编辑模式和命令模式："
                    }
                ]
            },
            "bbox": [
                179,
                605,
                653,
                620
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1）一般模式。以 vi 打开一个文件就直接进入一般模式了(这是默认的模式)。在这个模式中， 你可以使用『上下左右』按键来移动光标，你可以使用『删除字符』戒『删除整行』来处理文件内容， 也可以使用『复制、贴贴』来处理你的文件数据。"
                    }
                ]
            },
            "bbox": [
                144,
                623,
                848,
                676
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "即在一般模式中可以进行删除、复制、粘贴等动作，但却无法编辑文件的内容。"
                    }
                ]
            },
            "bbox": [
                179,
                678,
                794,
                694
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（2）编辑模式。在一般模式下，按下『i, I, o, O, a, A, r, R』等任何一个字母后就会进入编辑模式。通常，在按下这些字母后，在画面的左下方会出现『 INSERT 或 REPLACE 』的字样，此时才可以进行编辑。而要回到一般模式，则必须按下『 ESC 』按键，即可退出编辑模式，返回一般模式。"
                    }
                ]
            },
            "bbox": [
                144,
                697,
                847,
                769
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "而读取、保存、大量字符替换、离开 vi、显示行号等操作也是在该模式下完成的。"
                    }
                ]
            },
            "bbox": [
                179,
                771,
                811,
                785
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3. 使用范例"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                800,
                287,
                814
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "范例1："
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                827,
                278,
                841
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1）在Linux命令行界面下输入命令：vi ccc.c 后便进入vi的一般模式。如图5-1所示，vi的界面分为上下两部分，上半部分显示的是文件的实际内容，而下半部，即最下面的一行则显示一些状态信息。如果 ccc.c是一个原来不存在的文件，状态行中会显示『“ccc.c” [New"
                    }
                ]
            },
            "bbox": [
                144,
                846,
                850,
                898
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "File] 』表示它是一个新文件，否则，会显示出被编辑文件的行数、字符数等信息。"
                    }
                ]
            },
            "bbox": [
                144,
                85,
                781,
                101
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（2）按 “i”进入编辑模式，此时，状态行中会出现『 INSERT』的字样，便可以开始编辑文字了。此时，你输入的除了“ESC”以外的所有信息都被视为文件的内容，比如你可以输入："
                    }
                ]
            },
            "bbox": [
                144,
                104,
                848,
                154
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "include<stdio.h>   \nmain(){ printf(\"Hello,World!\\n\");   \n} "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                179,
                161,
                398,
                231
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）按“ESC”回到一般模式，此时，状态行中的『 INSERT』不见了。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）在一般模式中输入“：wq”保存文件的内容并离开vi。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                188,
                234,
                719,
                268
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "范例 2"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                288,
                270,
                304
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）在 Linux 命令行界面下输入命令： vi file1.txt"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）按 “i”进入编辑模式，输入下列字符，并保存文件。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                307,
                630,
                342
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "You raise me up, so I can stand on mountains;  \nYou raise me up, to walk on stormy seas;  \nI am strong, when I am on your shoulders;  \nYou raise me up: To more than I can be. "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                179,
                346,
                512,
                416
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "范例 3"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                438,
                270,
                451
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "通过vi编辑器编辑一个 systemcall.c文件，其内容如下："
                    }
                ]
            },
            "bbox": [
                181,
                456,
                608,
                470
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "include <fcntl.h>   \n#include<stdio.h>   \nint main(){ int fd=0，i; charbuf[10]; fd=open(\"file1.txt\",O_RDONLY); if(fd==-1)printf(\"Cannot open file!\\n\"); while((i=read(fd,buf,sizeof(buf)-1)>0){ buf[i]='\\0'; printf(\"%s\",buf); }   \n}"
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                181,
                476,
                509,
                712
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）按“ESC”回到一般模式。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）在一般模式中输入“：wq”保存文件的内容并离开vi。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                715,
                636,
                750
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4. 一般模式下的常用按键"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                762,
                394,
                778
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（1）光标移动"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                790,
                302,
                804
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "vi可以直接用键盘上的光标键来上下左右移动，但正规的 vi是用小写英文字母 。h、j、k、l，分别控制光标左、下、上、右移一格。"
                    }
                ]
            },
            "bbox": [
                179,
                808,
                805,
                843
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "按 Ctrl+B：屏幕往后移动一页。[常用] "
                    }
                ]
            },
            "bbox": [
                181,
                845,
                473,
                860
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "按Ctrl+F：屏幕往前移动一页。[常用] "
                    }
                ]
            },
            "bbox": [
                181,
                864,
                473,
                879
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "按Ctrl+U：屏幕往后移动半页。"
                    }
                ]
            },
            "bbox": [
                181,
                883,
                420,
                897
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "按 Ctrl+D：屏幕往前移动半页。"
                    }
                ]
            },
            "bbox": [
                181,
                86,
                421,
                101
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "按 0 (数字零)：移动文章的开头。[常用] "
                    }
                ]
            },
            "bbox": [
                181,
                104,
                495,
                121
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "按 G：移动到文章的最后。[常用] "
                    }
                ]
            },
            "bbox": [
                181,
                123,
                447,
                139
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "按 w：光标跳到下个单词的开头。[常用] "
                    }
                ]
            },
            "bbox": [
                181,
                141,
                500,
                156
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "按 e：光标跳到下个单词的字尾。"
                    }
                ]
            },
            "bbox": [
                181,
                160,
                440,
                175
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "按 b：光标回到上个单词的开头。"
                    }
                ]
            },
            "bbox": [
                181,
                179,
                440,
                193
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "按 $：移到光标所在行的行尾。[常用]"
                    }
                ]
            },
            "bbox": [
                181,
                197,
                480,
                212
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "按 ^：移到该行第一个非空白的字符。"
                    }
                ]
            },
            "bbox": [
                181,
                216,
                475,
                230
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "按 0：移到该行的开头位置。[常用]"
                    }
                ]
            },
            "bbox": [
                181,
                234,
                463,
                250
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "按 #：移到该行的第#个位置，例：51、121。[常用]"
                    }
                ]
            },
            "bbox": [
                181,
                253,
                586,
                268
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（2）删除"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                271,
                267,
                286
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "x：每按一次删除光标所在位置的后面一个字符。[常用]"
                    }
                ]
            },
            "bbox": [
                179,
                290,
                611,
                306
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#x：例如，6x 表删除光标所在位置的后面 6 个字符。[常用]"
                    }
                ]
            },
            "bbox": [
                179,
                309,
                643,
                324
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "X：大字的 X，每按一次删除光标所在位置的前面一个字符。"
                    }
                ]
            },
            "bbox": [
                179,
                326,
                640,
                342
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#X：例如，20X 表删除光标所在位置的前面 20 个字符。"
                    }
                ]
            },
            "bbox": [
                181,
                344,
                610,
                361
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "dd：删除光标所在行。[超常用]"
                    }
                ]
            },
            "bbox": [
                181,
                363,
                428,
                380
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#dd：例如，6dd 表删除从光标所在的该行往下数 6 行之文字。[常用]"
                    }
                ]
            },
            "bbox": [
                179,
                382,
                714,
                399
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "(3)复制 与粘贴"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                401,
                304,
                416
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "yw：将光标所在处到字尾的字符复制到缓冲区中。"
                    }
                ]
            },
            "bbox": [
                179,
                420,
                566,
                435
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "yy：复制光标所在行。[超常用]"
                    }
                ]
            },
            "bbox": [
                179,
                439,
                425,
                454
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#yy：如：6yy 表示拷贝从光标所在的该行往下数 6 行之文字。[常用]"
                    }
                ]
            },
            "bbox": [
                181,
                456,
                710,
                473
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "p：将已复制的内容粘贴在光标后的位置"
                    }
                ]
            },
            "bbox": [
                181,
                475,
                495,
                491
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "P：将已复制的内容粘贴在光标前的位置"
                    }
                ]
            },
            "bbox": [
                181,
                493,
                495,
                508
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "(4)替换 "
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                512,
                240,
                527
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "r： 取代光标所在处的字符：[常用]"
                    }
                ]
            },
            "bbox": [
                181,
                531,
                458,
                546
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "R：取代字符直到按 Esc为止。"
                    }
                ]
            },
            "bbox": [
                181,
                550,
                411,
                564
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "(5)撤销和重做 "
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                568,
                295,
                583
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "u：假如您误操作一个指令，可以马上按 u，可撤销前一个操作。[超常用]"
                    }
                ]
            },
            "bbox": [
                181,
                586,
                749,
                602
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "U：撤销当前行上最近的所有操作。"
                    }
                ]
            },
            "bbox": [
                181,
                605,
                450,
                620
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "ctrl+r：重做上一个操作。"
                    }
                ]
            },
            "bbox": [
                181,
                624,
                373,
                638
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": ".： 点号可以重复执行上一次的指令。"
                    }
                ]
            },
            "bbox": [
                181,
                642,
                470,
                657
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "(6)更改 "
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                661,
                240,
                676
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "cw：更改光标所在处的字到字尾$处。"
                    }
                ]
            },
            "bbox": [
                181,
                678,
                468,
                694
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "c#w：例如，c3w 代表更改 3 个字。"
                    }
                ]
            },
            "bbox": [
                181,
                697,
                450,
                713
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "(7)切换到编辑模式"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                715,
                339,
                731
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "i ：进入插入模式，在当前光标前插入"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "I ：进入插入模式，在当前行首插入"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "a：进入插入模式，在当前光标后插入"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "A ：进入插入模式，在当前行尾插入"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "o：进入插入模式，在当前行之下新开一行"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "O：进入插入模式，在当前行之上新开一行"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "r：进入替换模式，替换当前字符 "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "R：进入替换模式，替换当前字符及其后的字符，直至按 ESC键 "
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                181,
                734,
                670,
                879
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5. 命令模式下的常用命令"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                892,
                394,
                907
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在一般模式下，按“:”便可切换到命令模式，然后可以使用下述命令模式下的命令："
                    }
                ]
            },
            "bbox": [
                179,
                85,
                823,
                101
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "q 命令：在没有任何修改操作发生的情况下，该命令可以退出 vi 编辑器。"
                    }
                ]
            },
            "bbox": [
                179,
                104,
                741,
                120
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "q!命令：不保存文件，强制退出 vi编辑器。"
                    }
                ]
            },
            "bbox": [
                179,
                123,
                512,
                137
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "w命令：保存文件。"
                    }
                ]
            },
            "bbox": [
                179,
                141,
                334,
                156
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "wq命令：保存文件，然后退出vi编辑器"
                    }
                ]
            },
            "bbox": [
                179,
                160,
                500,
                175
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "w[文件名] 命令：将编辑后的文件另存到指定文件中。"
                    }
                ]
            },
            "bbox": [
                179,
                179,
                600,
                193
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "r[文件名] 命令：将指定文件的内容读入，并添加到当前文件光标所在的位置后面。"
                    }
                ]
            },
            "bbox": [
                179,
                196,
                821,
                212
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4.2.4 Linux 环境下 C 编程"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                225,
                435,
                240
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. GCC 编译器"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                262,
                312,
                277
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（1）gcc 概述"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                290,
                295,
                306
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "GCC 是 linux 下最常用的编译器，也能运行在 unix、solaris、windows 等下，支持多种语言的编译，如C、 "
                    },
                    {
                        "type": "equation_inline",
                        "content": "{ \\mathsf { C } } { + } { + }"
                    },
                    {
                        "type": "text",
                        "content": "、Object C 等语言编写的程序。"
                    }
                ]
            },
            "bbox": [
                144,
                307,
                848,
                342
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "gcc对文件的处理需要经过预处理 "
                    },
                    {
                        "type": "equation_inline",
                        "content": "- >"
                    },
                    {
                        "type": "text",
                        "content": "编译- "
                    },
                    {
                        "type": "equation_inline",
                        "content": "- >"
                    },
                    {
                        "type": "text",
                        "content": "汇编 "
                    },
                    {
                        "type": "equation_inline",
                        "content": "^ { - > }"
                    },
                    {
                        "type": "text",
                        "content": "链接的步骤，从而产生一个可执行文件。预处理阶段主要是在库中寻找头文件，包含到待编译的文件中；编译阶段检查程序的语法；汇编阶段将源代码翻译成机器语言；链接阶段将所有的目标代码连接成一个可执行程序。各阶段对应不同的文件类型，具体如下："
                    }
                ]
            },
            "bbox": [
                144,
                344,
                853,
                416
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "file.c c 程序源文件"
                    }
                ]
            },
            "bbox": [
                179,
                420,
                374,
                435
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "file.i c程序预处理后文件"
                    }
                ]
            },
            "bbox": [
                179,
                438,
                431,
                453
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "file.cxx "
                    },
                    {
                        "type": "equation_inline",
                        "content": "{ \\mathsf { C } } { \\mathsf { + + } }"
                    },
                    {
                        "type": "text",
                        "content": "程序源文件，也可以是 file.cc / file.cpp / file.c++"
                    }
                ]
            },
            "bbox": [
                179,
                456,
                643,
                472
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "file.ii "
                    },
                    {
                        "type": "equation_inline",
                        "content": "{ \\mathsf { C } } { \\mathsf { + + } }"
                    },
                    {
                        "type": "text",
                        "content": "程序预处理后文件"
                    }
                ]
            },
            "bbox": [
                179,
                475,
                440,
                489
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "file.h "
                    },
                    {
                        "type": "equation_inline",
                        "content": "{ \\mathsf { c } } / { \\mathsf { c } } { + } { + }"
                    },
                    {
                        "type": "text",
                        "content": "头文件"
                    }
                ]
            },
            "bbox": [
                181,
                494,
                366,
                508
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "file.s 汇编程序文件"
                    }
                ]
            },
            "bbox": [
                181,
                512,
                378,
                527
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "file.o 目标代码文件"
                    }
                ]
            },
            "bbox": [
                181,
                531,
                381,
                546
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（2）GCC 使用格式："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                549,
                342,
                564
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "gcc [参数选项] [文件名] "
                    }
                ]
            },
            "bbox": [
                179,
                568,
                366,
                583
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "其中文件名是要编译的文件名称。"
                    }
                ]
            },
            "bbox": [
                181,
                586,
                440,
                601
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（3）GCC遵循的部分后缀越大规则："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                605,
                465,
                620
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "当调用gcc时，gcc根据待编译文件的扩展名（后缀）自动识别文件的类别，并调用对应的编译器。Gcc遵循的部分后缀约定规则如表所示："
                    }
                ]
            },
            "bbox": [
                179,
                623,
                848,
                656
            ]
        },
        {
            "type": "table",
            "content": {
                "image_source": {
                    "path": "images/4d7da42029b734d47a6d2ae6b049a39e16785ea00b3a621db5bacb8c39747492.jpg"
                },
                "table_caption": [],
                "table_footnote": [],
                "html": "<table><tr><td>后缀</td><td>约定规则</td></tr><tr><td>.c</td><td>C语言源代码文件</td></tr><tr><td>.a</td><td>由目标文件构成的档案库文件</td></tr><tr><td>.C .cc .cxx</td><td>C++源代码文件</td></tr><tr><td>.h</td><td>程序包含的头文件</td></tr><tr><td>.i</td><td>已经预处理过的C源代码文件</td></tr><tr><td>.ii</td><td>已经预处理过的C++源代码文件</td></tr><tr><td>.m</td><td>Objective-C源代码文件</td></tr><tr><td>.o</td><td>编译后的目标文件</td></tr><tr><td>.s</td><td>汇编语言源代码文件</td></tr><tr><td>.S</td><td>经过预编译的汇编语言源代码文件</td></tr></table>",
                "table_type": "simple_table",
                "table_nest_level": 1
            },
            "bbox": [
                178,
                658,
                818,
                871
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（4）GCC的参数说明："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                890,
                359,
                904
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "GCC 参数很多，最常用的参数如下："
                    }
                ]
            },
            "bbox": [
                179,
                86,
                455,
                101
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-c 仅编译或汇编，生成目标代码文件，将.c、.i、.s 等文件生成.o 文件，其余文件被忽略"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-S 仅编译，不进行汇编和链接，将.c、.i等文件生成.s文件，其余文件被忽略"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-E 仅预处理，并发送预处理后的.i文件到标准输出，其余文件被忽略"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-o file 创建可执行文件并保存在 file 中，而不是默认文件 a.out"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-g 产生用于调试和排错的扩展符号表，用于GDB 调试，切记-g和-O通常不能一起使用"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                215,
                104,
                848,
                231
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-w 取消所有警告"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-W 给出更详细的警告"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-O [num] 优化，可以指定 0-3 作为优化级别，级别 0 表示没有优化"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-x language 默认为-x none，即依靠后缀名确定文件类型，加上-x lan 确定后面所有文件类型，直到下一个-x出现为止"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-I dir 将 dir 目录加到搜寻头文件的目录中去，并优先于gcc中缺省的搜索目录，有多个-I选项时，按照出现顺序搜索"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-L dir 将 dir 目录加到搜索-lname 选项指定的函数库文件的目录列表中去，并优先于gcc缺省的搜索目录，有多个-L 选项时，按照出现顺序搜索"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "-lname 在链接时使用函数库libname.a，链接程序在-Ldir 指定的目录和/lib、/usr/lib目录下寻找该库文件，在没有使用-static选项时，如果发现共享函数库libname.so，则使用 libname.so 进行动态链接"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                216,
                234,
                855,
                454
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "-fPIC 产生位置无关的目标代码，可用于构造共享函数库"
                    }
                ]
            },
            "bbox": [
                226,
                456,
                724,
                470
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "-static 禁止与共享函数库链接 "
                    }
                ]
            },
            "bbox": [
                226,
                476,
                507,
                489
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "-shared 尽量与共享函数库链接（默认）"
                    }
                ]
            },
            "bbox": [
                226,
                494,
                578,
                508
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（5）简单范例1"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                530,
                315,
                545
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "1）按“vi 编辑器”的简单范例 1，先通过 vi 编辑器编辑好文件 ccc.c。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "2）使用Linux命令行界面，在命令提示符后，输入命令："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                196,
                549,
                712,
                582
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "gcc ccc.c "
                    }
                ]
            },
            "bbox": [
                201,
                589,
                284,
                600
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "功能：对源程序 ccc.c进行编译链接，产生对应的可执行文件，文件名缺省为：a.out。"
                    }
                ]
            },
            "bbox": [
                210,
                605,
                836,
                619
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "也可以通过选项-o在编译命令中指定可执行文件名，如："
                    }
                ]
            },
            "bbox": [
                203,
                623,
                640,
                638
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "gcc -o ccc ccc.c "
                    }
                ]
            },
            "bbox": [
                203,
                645,
                329,
                657
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "将产生可执行文件 ccc，而不是默认的 a.out。"
                    }
                ]
            },
            "bbox": [
                189,
                659,
                537,
                675
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "3）在命令提示符后，输入命令：./a.out 或 ./ccc 运行当前目录下可执行文件 a.out（或ccc）。"
                    }
                ]
            },
            "bbox": [
                154,
                678,
                848,
                712
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "上述范例的运行结果如下图所示。"
                    }
                ]
            },
            "bbox": [
                183,
                715,
                440,
                731
            ]
        },
        {
            "type": "image",
            "content": {
                "image_source": {
                    "path": "images/8ed87e5f78e622d01fd77b4113f203bbd7af2478750a827f77d71e61f9b2c529.jpg"
                },
                "image_caption": [],
                "image_footnote": []
            },
            "bbox": [
                147,
                738,
                868,
                882
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "证你的理解是否正确。"
                    }
                ]
            },
            "bbox": [
                147,
                883,
                317,
                897
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "3）思考上述程序中文件打开操作和读文件操作到底是谁具体完成的，并用 man查阅open，read，printf，了解它们的具体功能、函数参数和返回值等信息，并注意它们属于系统调用，还是库函数，以加速对系统调用概念的理解。"
                    }
                ]
            },
            "bbox": [
                144,
                85,
                848,
                137
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（7）简单范例 3"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                142,
                317,
                156
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "编译多个源文件。"
                    }
                ]
            },
            "bbox": [
                181,
                160,
                317,
                175
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "1） 使用 vi/vim 编辑器编写两个文件：message.c，main.c："
                    }
                ]
            },
            "bbox": [
                189,
                179,
                636,
                193
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "vi message.c  \nvi main.c "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                242,
                198,
                364,
                230
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "2）使用 gcc 编译："
                    }
                ]
            },
            "bbox": [
                189,
                234,
                329,
                249
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "gcc -c message.c //输出message.o文件，是一个已编译的目标代码文件gcc -c main.c //输出main.o文件"
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                189,
                252,
                847,
                287
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "gcc -o all main.o message.o //执行连接阶段的工作，然后生成可执行文件 all"
                    }
                ]
            },
            "bbox": [
                189,
                290,
                848,
                306
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "3）执行可执行文件："
                    }
                ]
            },
            "bbox": [
                189,
                309,
                352,
                323
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "./all "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                218,
                328,
                257,
                342
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "注意：：gcc 对如何将多个源文件编译成一个可执行文件有内置的规则，所以前面的多个单独步骤可以简化为一个命令："
                    }
                ]
            },
            "bbox": [
                144,
                344,
                847,
                379
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "gcc -o all message.c main.c "
                    }
                ],
                "code_language": "batch"
            },
            "bbox": [
                171,
                382,
                425,
                399
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. gdb 调试工具"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                411,
                324,
                426
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "gdb 是一个 GNU 调试工具，可以调试 C 和 "
                    },
                    {
                        "type": "equation_inline",
                        "content": "{ \\mathsf { C } } { \\mathsf { + + } }"
                    },
                    {
                        "type": "text",
                        "content": "程序，其主要功能有：1）监视程序中变量的值；2）设置断点；3）单步执行程序。"
                    }
                ]
            },
            "bbox": [
                144,
                438,
                847,
                470
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "为了能够使用gdb 调试程序，必须在编译时包含调试信息，即使用gcc编译时需要加上“-g”选修，如 gcc –g –o test test.c。"
                    }
                ]
            },
            "bbox": [
                144,
                475,
                847,
                508
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "gdb 命令很多，下面列出一些常用的调试命令："
                    }
                ]
            },
            "bbox": [
                179,
                512,
                547,
                527
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（1）gdb 启动及退出："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                531,
                357,
                546
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "1）启动gdb命令：gdb exefilename "
                    }
                ]
            },
            "bbox": [
                200,
                549,
                465,
                565
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "其中 exefilename 是可执行文件名，如果没有指定运行程序，也可进入 gdb 后再用file命令装入文件。"
                    }
                ]
            },
            "bbox": [
                144,
                567,
                847,
                601
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "gdb 启动成功后，提示符为：（gdb），随后可以输入gdb 命令对程序进行调试。"
                    }
                ]
            },
            "bbox": [
                188,
                605,
                826,
                620
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "2）退出 gdb 命令：(gdb)quit"
                    }
                ]
            },
            "bbox": [
                194,
                624,
                435,
                639
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（2）断点管理命令："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                642,
                344,
                657
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1）设置断点："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                659,
                304,
                675
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "break命令（可简写为b）可以用来在调试的程序中设置断点，该命令有如下四种形式："
                    }
                ]
            },
            "bbox": [
                174,
                678,
                847,
                712
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb)break line-number 使程序在执行给定行之前停止。"
                    }
                ]
            },
            "bbox": [
                174,
                715,
                640,
                731
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb)break function-name 使程序在进入指定的函数之前停止。"
                    }
                ]
            },
            "bbox": [
                174,
                734,
                695,
                750
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb)break line-or-function if condition 如果 condition（条件）是真，程序到达指定行或函数时停止。"
                    }
                ]
            },
            "bbox": [
                174,
                753,
                847,
                785
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb) break routine-name 在指定例程的入口处设置断点"
                    }
                ]
            },
            "bbox": [
                174,
                790,
                650,
                806
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如果该程序是由很多原文件构成的，你可以在各个原文件中设置断点，而不是在当前的原文件中设置断点，其方法如下："
                    }
                ]
            },
            "bbox": [
                174,
                809,
                847,
                841
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb) break filename:line-number "
                    }
                ]
            },
            "bbox": [
                174,
                847,
                482,
                862
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb) break filename:function-name "
                    }
                ]
            },
            "bbox": [
                174,
                865,
                502,
                879
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2）从断点处继续执行："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                85,
                374,
                101
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb) countinue "
                    }
                ]
            },
            "bbox": [
                184,
                105,
                332,
                121
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3）显示当前 gdb 的断点信息："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                141,
                438,
                156
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb) info break "
                    }
                ]
            },
            "bbox": [
                189,
                160,
                339,
                177
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4）删除指定的某个断点："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                196,
                391,
                212
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb) delete breakpoint 1 "
                    }
                ]
            },
            "bbox": [
                189,
                216,
                421,
                231
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "该命令将会删除编号为 1 的断点，如果不带编号参数，将删除所有的断点："
                    }
                ]
            },
            "bbox": [
                189,
                234,
                766,
                249
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb) delete breakpoint "
                    }
                ]
            },
            "bbox": [
                189,
                253,
                405,
                269
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5）禁止使用某个断点"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                288,
                366,
                305
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb) disable breakpoint 1 "
                    }
                ]
            },
            "bbox": [
                189,
                309,
                428,
                325
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "该命令将禁止断点 1"
                    }
                ]
            },
            "bbox": [
                189,
                326,
                352,
                341
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "6）允许使用某个断点"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                344,
                366,
                361
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb) enable breakpoint 1 "
                    }
                ]
            },
            "bbox": [
                189,
                363,
                425,
                381
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "该命令将允许断点 1"
                    }
                ]
            },
            "bbox": [
                189,
                382,
                354,
                397
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "7）清除原文件中某一代码行上的所有断点"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                400,
                526,
                416
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb)clean number "
                    }
                ]
            },
            "bbox": [
                189,
                420,
                366,
                436
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "注：number 为原文件的某个代码行的行号"
                    }
                ]
            },
            "bbox": [
                189,
                438,
                534,
                453
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（3）显示信息命令："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                475,
                344,
                489
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1）print 命令："
                    }
                ],
                "level": 1
            },
            "bbox": [
                203,
                494,
                329,
                508
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "利用 print 命令可以检查各个变量的值。"
                    }
                ]
            },
            "bbox": [
                203,
                512,
                517,
                527
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb) print p //(p 为变量名或表达式) "
                    }
                ]
            },
            "bbox": [
                203,
                531,
                564,
                546
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb) print 开始表达式@连续内存空间大小 "
                    }
                ]
            },
            "bbox": [
                203,
                549,
                559,
                565
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "打印内存中某一连续内存空间的值，主要用于打印数组类型的表达式的值。"
                    }
                ]
            },
            "bbox": [
                223,
                567,
                801,
                583
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb) print 程序中的某一函数调用"
                    }
                ]
            },
            "bbox": [
                208,
                586,
                494,
                602
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "如：(gdb) print find_entry(1,0)"
                    }
                ]
            },
            "bbox": [
                225,
                605,
                502,
                621
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2）whatis 命令：可以显示某个变量的类型"
                    }
                ],
                "level": 1
            },
            "bbox": [
                216,
                640,
                574,
                657
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb) whatis p //(p 为变量) "
                    }
                ]
            },
            "bbox": [
                216,
                659,
                485,
                676
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "type "
                    },
                    {
                        "type": "equation_inline",
                        "content": "="
                    },
                    {
                        "type": "text",
                        "content": "int * "
                    }
                ]
            },
            "bbox": [
                216,
                678,
                327,
                695
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3）display 命令：设置要显示的表达式"
                    }
                ],
                "level": 1
            },
            "bbox": [
                216,
                715,
                542,
                732
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb)display 表达式 //当程序运行到断点时，显示该表达式的值。"
                    }
                ]
            },
            "bbox": [
                216,
                734,
                779,
                751
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb)info display：显示所有要显示表达式的值。"
                    }
                ]
            },
            "bbox": [
                216,
                753,
                608,
                769
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb)undisplay 表达式：结束已设置的表达式。"
                    }
                ]
            },
            "bbox": [
                216,
                771,
                600,
                788
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "4）awatch 命令：设置要监视的表达式"
                    }
                ]
            },
            "bbox": [
                216,
                790,
                532,
                806
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "(gdb)awatch 表达式"
                    }
                ]
            },
            "bbox": [
                200,
                808,
                379,
                825
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "当表达式的值变化或被读取时，程序暂停，显示表达式的值。"
                    }
                ]
            },
            "bbox": [
                200,
                827,
                670,
                843
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（4）程序运行控制命令："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                864,
                379,
                879
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "1）run：运行程序"
                    }
                ]
            },
            "bbox": [
                203,
                883,
                354,
                897
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "2）kill：结束程序的调试运行"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "3）cont：继续执行程序"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "4）next：单步运行，不进入子程序"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "5）step：单步运行，进入子程序 "
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                201,
                85,
                487,
                156
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（5）文件命令："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                178,
                309,
                193
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "1）file命令：加载调试文件file 文件名"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "2）list 命令：列出文件内容 list [参数] "
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                201,
                197,
                426,
                268
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "参数说明："
                    }
                ]
            },
            "bbox": [
                189,
                271,
                272,
                285
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "参数为空：从上次显示的最后一行或附近开始，显示 10 行"
                    }
                ]
            },
            "bbox": [
                189,
                288,
                650,
                305
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "<行号>：从当前文件的该行开始显示"
                    }
                ]
            },
            "bbox": [
                189,
                307,
                489,
                323
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "<文件名> <行号 "
                            },
                            {
                                "type": "equation_inline",
                                "content": ">"
                            },
                            {
                                "type": "text",
                                "content": "：从指定文件的指定行开始显示"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "<函数名 "
                            },
                            {
                                "type": "equation_inline",
                                "content": ">"
                            },
                            {
                                "type": "text",
                                "content": "：显示指定的函数"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "<文件名> <函数名 "
                            },
                            {
                                "type": "equation_inline",
                                "content": ">"
                            },
                            {
                                "type": "text",
                                "content": "：指定文件的指定函数"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "<行号 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "1 > <"
                            },
                            {
                                "type": "text",
                                "content": "<行号 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "^ { 2 > }"
                            },
                            {
                                "type": "text",
                                "content": "：从行号 1 显示到行号 2"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                326,
                594,
                397
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（6）堆栈相关命令："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                419,
                344,
                435
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "1）backtrace 命令：可简写为 bt，显示栈中内容。"
                    }
                ]
            },
            "bbox": [
                189,
                438,
                601,
                453
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "命令：bt: 显示当前函数调用栈的所有信息。"
                    }
                ]
            },
            "bbox": [
                189,
                456,
                573,
                470
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "命令：bt "
                    },
                    {
                        "type": "equation_inline",
                        "content": "< \\mathsf { n } > : \\mathsf { n }"
                    },
                    {
                        "type": "text",
                        "content": "是一个正整数，表示只打印栈顶上 n 层的栈信息。"
                    }
                ]
            },
            "bbox": [
                189,
                475,
                719,
                489
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "n是一个负整数，表示只打印栈底下n 层的栈信息。"
                    }
                ]
            },
            "bbox": [
                321,
                494,
                719,
                508
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "2）frame命令：可简写为f，显示当前栈层的信息："
                    }
                ]
            },
            "bbox": [
                188,
                512,
                603,
                527
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "显示的内容有：栈的层编号，当前的函数名，函数参数值，函数所在文件及行号，函数执行到的语句。"
                    }
                ]
            },
            "bbox": [
                144,
                533,
                848,
                570
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "info frame（或 info f）："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                574,
                413,
                589
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "显示出更为详细的当前栈层的信息，只不过大多数都是运行时的内内地址。比如：函数地址，调用函数的地址，被调用函数的地址，目前的函数是由什么样的程序语言写成的、函数参数地址及值、局部变量的地址等等。"
                    }
                ]
            },
            "bbox": [
                144,
                596,
                848,
                653
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4.3 Linux 管道通信机制"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                680,
                465,
                699
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "管道是所有UNIX 及linux都提供的一种进程间通信机制，它是进程之间的一个单向数据流，一个进程可向管道写入数据，另一个进程则可以从管道中读取数据，从而达到进程通信的目的。"
                    }
                ]
            },
            "bbox": [
                144,
                730,
                848,
                788
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4.3.1 无名管道"
                    }
                ],
                "level": 1
            },
            "bbox": [
                184,
                800,
                315,
                815
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. 无名管道概念"
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                827,
                294,
                843
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "无名管道通过pipe()系统调用创建，它具有如下特点："
                    }
                ]
            },
            "bbox": [
                181,
                846,
                593,
                862
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）它只能用于具有亲缘关系的进程（如父子进程或者兄弟进程）之间的通信。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）管道是半双工的，具有固定的读端和写端。虽然 pipe()系统调用返回了两个文件描述"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                154,
                865,
                848,
                898
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "符，但每个进程在使用一个文件描述符之前仍需先将另一个文件描述符关闭。如果需要双向的数据流，则必须通过两次 pipe()建立起两个管道。"
                    }
                ]
            },
            "bbox": [
                188,
                85,
                848,
                120
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（3）管道可以看成是一种特殊的文件，对管道的读写与文件的读写一样使用普通的 read、write等函数，但它不是普通的文件，也不属于任何文件系统，而只存在于内存中。"
                    }
                ]
            },
            "bbox": [
                152,
                123,
                848,
                156
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. pipe 系统调用"
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                160,
                294,
                175
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1）函数原型"
                    }
                ]
            },
            "bbox": [
                154,
                179,
                268,
                193
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "include <unistd.h> int pipe(int fileds[2]); "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                206,
                198,
                373,
                231
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（2）参数"
                    }
                ]
            },
            "bbox": [
                154,
                234,
                231,
                249
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Filedes[2]参数：是一个输出参数，它返回两个文件描述符，其中filedes[0]指向管道的读端，filedes[1]指向管道的写端。"
                    }
                ]
            },
            "bbox": [
                144,
                256,
                843,
                293
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（3）功能"
                    }
                ]
            },
            "bbox": [
                154,
                296,
                231,
                310
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "pipe在内存缓冲区中创建一个管道，并将读写该管道的一对文件描述符保存在filedes所指的数组中，其中filedes[0]用于读管道，filedes[1]用于写管道。"
                    }
                ]
            },
            "bbox": [
                144,
                318,
                848,
                355
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（4）返回值"
                    }
                ]
            },
            "bbox": [
                154,
                357,
                250,
                372
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "成功返回0；失败返回-1，并在error中存入错误码。"
                    }
                ]
            },
            "bbox": [
                146,
                375,
                549,
                391
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（5）错误代码"
                    }
                ]
            },
            "bbox": [
                154,
                394,
                268,
                409
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EMFILE：进程使用的文件描述符过多"
                    }
                ]
            },
            "bbox": [
                146,
                412,
                433,
                426
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "ENFILE ：系统文件表已满"
                    }
                ]
            },
            "bbox": [
                206,
                431,
                413,
                445
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EFAULT ：非法参数 filedes"
                    }
                ]
            },
            "bbox": [
                206,
                450,
                413,
                464
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3. 无名管道的阻塞型读写"
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                468,
                364,
                483
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "管道缓冲区有4096B的长度限制，因此，采用阻塞型读写方式时，当管道已经写满时，写进程必须等待，直到读进程取走信息为止。同样，读空的管道时，也可能会引起进程阻塞。"
                    }
                ]
            },
            "bbox": [
                144,
                489,
                847,
                527
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "当管道大小（管道缓冲区中待读的字节数）为 p，而用户进程请求读n个字节时："
                    }
                ]
            },
            "bbox": [
                181,
                533,
                808,
                549
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "若不存在写进程："
                    }
                ]
            },
            "bbox": [
                144,
                554,
                282,
                570
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\scriptstyle { \\mathsf { p } } = 0"
                            },
                            {
                                "type": "text",
                                "content": "，则返回 0；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "0<p<n，则读得 p 个字节，返回 p，管道缓冲区中还剩 0 个字节；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "equation_inline",
                                "content": "{ \\mathsf { p } } \\geq { \\mathsf { n } }"
                            },
                            {
                                "type": "text",
                                "content": "，则读得 n 个字节，返回 n，管道缓冲区中还剩 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "{ \\mathsf { p } } - { \\mathsf { n } }"
                            },
                            {
                                "type": "text",
                                "content": "个字节；"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                571,
                685,
                625
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "若存在写进程，且写进程没因写管道而阻塞时："
                    }
                ]
            },
            "bbox": [
                144,
                627,
                510,
                643
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\scriptstyle { \\mathsf { p } } = 0"
                            },
                            {
                                "type": "text",
                                "content": "，读进程阻塞等待数据被写入管道；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "0<p<n，则读得 p 个字节，返回 p，管道缓冲区中还剩 0 个字节；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "equation_inline",
                                "content": "{ \\mathsf { p } } \\geq { \\mathsf { n } }"
                            },
                            {
                                "type": "text",
                                "content": "，则读得 n 个字节，返回 n，管道缓冲区中还剩 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "{ \\mathsf { p } } - { \\mathsf { n } }"
                            },
                            {
                                "type": "text",
                                "content": "个字节；"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                646,
                685,
                699
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "若存在写进程，且写进程因写管道而阻塞时："
                    }
                ]
            },
            "bbox": [
                144,
                702,
                492,
                717
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1} 0 < p < n"
                            },
                            {
                                "type": "text",
                                "content": "，则读管道，当管道缓冲区变空时，阻塞，等待数据被写入。最后，返回实际读得的字节数；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled { 2 } { \\mathsf p } \\geqslant { \\mathsf n }"
                            },
                            {
                                "type": "text",
                                "content": "，则读得 n 个字节，返回 n，管道缓冲区中还剩 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "{ \\mathsf { p } } - { \\mathsf { n } }"
                            },
                            {
                                "type": "text",
                                "content": "个字节。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                720,
                848,
                772
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "当管道缓冲区中有 u个字节未用，而用户进程请求写入n个字节时："
                    }
                ]
            },
            "bbox": [
                206,
                775,
                732,
                791
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "若不存在读进程，则向写管道的进程将发SIGPIPE信号，并返回－EPIPE。"
                    }
                ]
            },
            "bbox": [
                144,
                794,
                704,
                809
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "若存在至少一个读进程："
                    }
                ]
            },
            "bbox": [
                144,
                813,
                334,
                828
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\mathsf { u } { < } \\mathsf { n } { \\leqslant } 4 0 9 6"
                            },
                            {
                                "type": "text",
                                "content": "则写进程等待，直到有 n-u 个字节被释放为止，写入 n 个字节，返回 n；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "equation_inline",
                                "content": "n { > } 4 0 9 6"
                            },
                            {
                                "type": "text",
                                "content": "则写入 n 个字节（必要时等待）并返回 n；"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                831,
                845,
                866
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "u≥n 写入n个字节，返回n。"
                    }
                ]
            },
            "bbox": [
                154,
                869,
                448,
                883
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4. 有名管道"
                    }
                ],
                "level": 1
            },
            "bbox": [
                144,
                887,
                258,
                902
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "管道应用的一个重大限制是它没有名字，因此，只能用于具有亲缘关系的进程间通信，在有名管道（named pipe或FIFO）提出后，该限制得到了克服。FIFO不同于管道之处在于它提供一个路径名与之关联，以 FIFO的文件形式存在于文件系统中。这样，即使与 FIFO的创建进程不存在亲缘关系的进程，只要可以访问该路径，就能够彼此通过FIFO相互通信（能够访问该路径的进程以及 FIFO的创建进程之间），因此，通过 FIFO不相关的进程也能交换数据。值得注意的是，FIFO严格遵循先进先出（first in first out），对管道及 FIFO的读总是从开始处返回数据，对它们的写则把数据添加到末尾。它们不支持诸如 lseek()等文件定位操作。"
                    }
                ]
            },
            "bbox": [
                144,
                89,
                852,
                254
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "有名管道通过mkfifo 创建："
                    }
                ]
            },
            "bbox": [
                181,
                256,
                391,
                272
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "include <sys/types.h>   \n#include <sys/stat.h>   \nint mkfifo(const char \\*pathname,mode_t mode) "
                    }
                ],
                "code_language": "cpp"
            },
            "bbox": [
                181,
                275,
                541,
                329
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "该函数的第一个参数是一个普通的路径名，也就是创建后 FIFO的名字。第二个参数与打开普通文件的open()函数中的mode 参数相同。 有名管道创建成功，mkfifo()返回 0；否则返回-1。如果mkfifo的第一个参数是一个已经存在的路径名时，错误代码中会返回EEXIST错误，所以一般典型的调用代码首先会检查是否返回该错误，如果确实返回该错误，那么只要调用打开FIFO的函数就可以了。"
                    }
                ]
            },
            "bbox": [
                144,
                335,
                847,
                435
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "与普通文件类似，有名管道在使用之前必须先进行open操作，具体类似于文件的打开方式："
                    }
                ]
            },
            "bbox": [
                144,
                442,
                847,
                478
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "include <sys/types.h>   \n#include <sys/stat.h>   \n#include <fcntl.h>   \nint open(const char \\*pathname,int flags); "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                181,
                481,
                485,
                552
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "对有名管道的open操作必须遵循下列规则：（1）如果当前打开操作是为读而打开 FIFO时，若已经有相应进程为写而打开该FIFO，则当前打开操作将成功返回；否则，可能阻塞直到有相应进程为写而打开该 FIFO（当前打开操作设置了阻塞标志）；或者，成功返回（当前打开操作没有设置阻塞标志）。（2）如果当前打开操作是为写而打开FIFO时，如果已经有相应进程为读而打开该FIFO，则当前打开操作将成功返回；否则，可能阻塞直到有相应进程为读而打开该FIFO（当前打开操作设置了阻塞标志）；或者，返回ENXIO 错误（当前打开操作没有设置阻塞标志）。"
                    }
                ]
            },
            "bbox": [
                144,
                558,
                848,
                702
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "一旦打开操作成功，便可通过返回的文件描述符，利用 read、write系统调用对管道进行读写操作，读写完成应使用 close系统调用关闭有名管道。"
                    }
                ]
            },
            "bbox": [
                144,
                708,
                848,
                745
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4.4 Linux 消息队列通信机制"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                771,
                512,
                790
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux系统中，若干个进程可以共享一个消息队列，系统允许其中的一个或多个进程向消息队列写入消息，同时也允许一个或多个进程从消息队列中读取消息，从而完成进程之间的信息交换，这种通信机制被称作消息队列通信机制。消息队列通信机制是客户/服务器模型中常用的进程通信方式：客户向服务器发送请求信息，服务器读取消息并执行相应的请求。"
                    }
                ]
            },
            "bbox": [
                144,
                821,
                848,
                902
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "消息可以是命令，也可以是数据。"
                    }
                ]
            },
            "bbox": [
                144,
                90,
                405,
                105
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1.数据结构"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                111,
                278,
                127
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（1）消息缓冲区 struct msgbuf"
                    }
                ],
                "level": 1
            },
            "bbox": [
                154,
                133,
                405,
                148
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "消息缓冲区是用来存放消息内容的结构体，而且这个结构体的第一个成员必须是一个大于0 的长整数，表示对应消息的类型；不过，系统对结构体中其余成员的类型不做任何限制。include/linux/msg.h 中给出的消息缓冲格式如下："
                    }
                ]
            },
            "bbox": [
                144,
                154,
                848,
                212
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "struct msgbuf{ /*消息定义的参照格式*/\n    long mtype; /*消息类型（大于0的长整数）\n    char mtext[1]; /*消息正文*/\n};"
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                181,
                218,
                726,
                297
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "应用程序员可以重新定义消息缓冲区结构体，其中，成员(mtext)不仅能定义为长度为1 的字符数组，也可以定义成长度大于 1的字符数组，或定义成其他的数据类型，Linux也允许消息正文的长度为 0，即结构体中没有mtext域。"
                    }
                ]
            },
            "bbox": [
                144,
                303,
                848,
                362
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "虽然，Linux没限定 mtext的类型，但却限定了消息的长度，一个消息的最大长度由宏MSGMAX决定，根据版本的不同，其取值可能为8192或其他值。"
                    }
                ]
            },
            "bbox": [
                144,
                368,
                848,
                405
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（2）消息结构 struct msg"
                    }
                ],
                "level": 1
            },
            "bbox": [
                154,
                411,
                359,
                426
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "消息队列中的每个消息节点中不仅包含了消息内容，还包含了一些其他信息，消息节点由消息结构来描述。include/linux/msg.h 中给出的消息结构格式如下："
                    }
                ]
            },
            "bbox": [
                146,
                432,
                848,
                469
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "struct msg {\n    struct msg *msg_next; /*消息队列链接指针，指向队列中的下一条消息 */\n    long msg_type; /*消息类型，同 struct msgbuf 中的 mtype*/\n    char *msgSpot; /*消息正文的地址，指向 msgbuf 的消息正文 */\n    time_t msg_stime; /*消息发送的时间 */\n    short msg-ts; /*消息正文的大小 */\n};"
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                181,
                475,
                796,
                618
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（3）IPC 对象访问权限 struct ipc_perm"
                    }
                ],
                "level": 1
            },
            "bbox": [
                154,
                625,
                472,
                640
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "struct ipcperm{  \nkey_t key; /* IPC对象键值*/  \nushort uid; /* owner euid and egid */  \nushort gid;  \nushort cuid; /* creator euid and egid */  \nushort cgid;  \nushort mode; /* 访问权限 */  \nushort seq; /* slot usage sequence number，即IPC对象使用频率信息*/};  \n其中："
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                181,
                646,
                786,
                852
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Key 是IPC对象（例如消息队列，共享存储器等）的键值，每个 IPC对象都关联着一个唯一的长整型的键值，不同的进程通过相同的键值可访问到同一个IPC对象。用户进程在创"
                    }
                ]
            },
            "bbox": [
                144,
                860,
                848,
                897
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "建IPC对象时可以指定 key为某个大于0的整数，此时，需要用户自己保证该 key值不与系统中存在的其他IPC键值相冲突。更常用的方式是通过函数调用 ftok（pathname，proj_jd）请求系统为用户进程生成一个键值，其中的pathname 是一个实际存在的文件的路径名，而且用户进程具有对该文件的访问权限，proj_jd是一个整数，但 ftok只会用到其低 8位的值（该值不能为0），只要路径名访问到的是同一个文件，而且 proj_jd的低8 位的值相同，则ftok()调用便将产生相同的键值；如果使用不同的文件路径名和 proj_jd，虽然系统不能保证、但通常生成的键值是不同的。"
                    }
                ]
            },
            "bbox": [
                144,
                89,
                852,
                235
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Mode 中给出了该IPC对象的访问权限，由9 个二进制位表示所有者、同组用户、其他组用户的访问权限。它可以是下列权限的组合："
                    }
                ]
            },
            "bbox": [
                144,
                239,
                850,
                278
            ]
        },
        {
            "type": "table",
            "content": {
                "image_source": {
                    "path": "images/627d7f2a996a73ea8988306bc1d29e9dd739dabc725aab29c2287e9412d65e10.jpg"
                },
                "table_caption": [],
                "table_footnote": [],
                "html": "<table><tr><td>访问权限</td><td>八进制整数</td></tr><tr><td>拥有者可读</td><td>0400</td></tr><tr><td>拥有者可写</td><td>0200</td></tr><tr><td>同组用户可读</td><td>0040</td></tr><tr><td>同组用户可写</td><td>0020</td></tr><tr><td>其他用户可读</td><td>0004</td></tr><tr><td>其他用户可写</td><td>0002</td></tr></table>",
                "table_type": "simple_table",
                "table_nest_level": 1
            },
            "bbox": [
                322,
                281,
                559,
                426
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "由于系统规定任何 IPC结构都不存在可执行权限，因此一个IPC对象的权限最大值为0666（八进制）。"
                    }
                ]
            },
            "bbox": [
                144,
                432,
                842,
                469
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（4）消息队列结构体 struct msqid_ds"
                    }
                ],
                "level": 1
            },
            "bbox": [
                154,
                475,
                458,
                491
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "系统中每个消息队列由一个 struct msqid_ds 类型的变量来描述，struct msqid_ds 的格式如下："
                    }
                ]
            },
            "bbox": [
                144,
                495,
                850,
                533
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "struct msqid_ds {\n    struct ipcperm msg_perm; /* 消息队列访问权限*/\n    struct msg *msg_first; /* 队列上第一条消息，即链表头*/\n    struct msg *msg_last; /* 队列中的最后一条消息，即链表尾*/\n    time_t msg_stime; /* 发送给队列的最后一条消息的时间 */\n    time_t msg_rtime; /* 从消息队列接收到最后一条消息的时间 */\n    time_t msg_ctime; /* 最后修改队列的时间*/\n}\n... \nushort msg_cbytes; /*队列上所有消息总的字节数 */\nushort msg_qnum; /*当前队列上消息的个数 */\nushort msg_qbytes; /* 队列允许的最大的字节数 */\nushort msg_lspid; /* 发送最后一条消息的进程的 pid */\nushort msg_lrpid; /* 接收最后一条消息的进程的 pid */\n};"
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                181,
                539,
                726,
                832
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux还通过宏MSGMNB限定了一个消息队列的最大长度（队列中所有消息总的字节数）。"
                    }
                ]
            },
            "bbox": [
                179,
                838,
                847,
                854
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2.消息队列相关的系统调用"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                860,
                401,
                876
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux提供了一组消息队列相关的系统调用来方便用户进行消息通信。"
                    }
                ]
            },
            "bbox": [
                179,
                881,
                719,
                897
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（1）msgget 系统调用"
                    }
                ],
                "level": 1
            },
            "bbox": [
                154,
                89,
                324,
                105
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\textcircled{1}"
                    },
                    {
                        "type": "text",
                        "content": "函数原型："
                    }
                ]
            },
            "bbox": [
                181,
                111,
                280,
                126
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "include <sys/types.h>   \n#include <sys/ipc.h>   \n#include <sys/msg.h>   \nint msgget(key_t key, int msgflg); "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                181,
                133,
                485,
                212
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\textcircled{2}"
                    },
                    {
                        "type": "text",
                        "content": "参数:"
                    }
                ]
            },
            "bbox": [
                181,
                218,
                245,
                233
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "key key 为 0(IPC_PRIVATE)，则创建一个新的消息队列；否则，key 为一个大于 0的长整数，它对应于消息队列的键值，通常是通过ftok()函数生成的。"
                    }
                ]
            },
            "bbox": [
                144,
                239,
                848,
                275
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msgflg 对消息队列的访问权限和控制命令的组合。其中访问权限见“IPC 对象访问权限 struct ipc_perm”部分的说明。而控制命令 IPC_CREAT 表示，如果 key 对应的消息队列不存在，则创建它；而 IPC_EXCL必须与IPC_CREATT一起使用，它表示：如果 key对应的消息队列不存在，则创建一个新的队列，否则返回-1。"
                    }
                ]
            },
            "bbox": [
                144,
                282,
                850,
                362
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "功能： 如果IPC_CREAT 单独使用，semget()为一个新创建的消息队列返回标识数，或者返回具有相同键值的已存在消息队列标识数。如果 IPC_EXCL与 IPC_CREAT 一起使用，要么创建一个新的队列并返回它的标识数，如果队列已存在，则返回-1。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "返回值：成功，返回消息队列的标识数；出错，返回-1，同时将错误代码存放在 error中。对于新创建的消息队列，其msqid_ds结构成员变量的初值设置如下："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                368,
                850,
                469
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msg_qnum、msg_lspid、msg_lrpid 设置为 0；"
                    }
                ]
            },
            "bbox": [
                186,
                475,
                537,
                491
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msg_stime、msg_rtime 设置为 0；"
                    }
                ]
            },
            "bbox": [
                179,
                497,
                440,
                512
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msg_ctime 设置为当前时间；"
                    }
                ]
            },
            "bbox": [
                179,
                518,
                400,
                533
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msg_qbytes 设成系统的限制值，即宏 MSGMNB；"
                    }
                ]
            },
            "bbox": [
                179,
                539,
                537,
                554
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msgflg 的读写权限写入 msg_perm.mode 中；"
                    }
                ]
            },
            "bbox": [
                179,
                561,
                514,
                576
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msg_perm结构的 uid和cuid成员被设置成当前进程的有效用ID，id和 cuid成员被设置成当前进程的有效组 ID。"
                    }
                ]
            },
            "bbox": [
                144,
                582,
                847,
                618
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\textcircled{5}"
                    },
                    {
                        "type": "text",
                        "content": "错误代码：EACCES：指定的消息队列已存在，但调用进程没有权限访问它"
                    }
                ]
            },
            "bbox": [
                179,
                624,
                769,
                640
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EEXIST：key 指定的消息队列已存在，而 msgflg 中同时指定 IPC_CREAT 和 IPC_EXCL 标志"
                    }
                ]
            },
            "bbox": [
                144,
                646,
                848,
                681
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "ENOENT：key 指定的消息队列不存在同时 msgflg 中没有指定 IPC_CREAT 标志"
                    }
                ]
            },
            "bbox": [
                179,
                688,
                773,
                703
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "ENOMEM：需要建立消息队列，但内存不足"
                    }
                ]
            },
            "bbox": [
                179,
                709,
                505,
                725
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "ENOSPC：需要建立消息队列，但已达到系统的限制"
                    }
                ]
            },
            "bbox": [
                179,
                731,
                574,
                746
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（2）msgsnd 系统调用"
                    }
                ],
                "level": 1
            },
            "bbox": [
                154,
                753,
                324,
                768
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\textcircled{1}"
                    },
                    {
                        "type": "text",
                        "content": "函数原型："
                    }
                ]
            },
            "bbox": [
                181,
                774,
                280,
                789
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "include <sys/types.h>   \n#include <sys/ipc.h>   \n#include <sys msg.h>   \nint mgsnd(int msqid, struct msgbuf \\*msgp,size_t msgsz,int msgflg); "
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                181,
                796,
                793,
                876
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\textcircled{2}"
                    },
                    {
                        "type": "text",
                        "content": "参数:"
                    }
                ]
            },
            "bbox": [
                181,
                881,
                245,
                896
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msqid 消息队列的标识数"
                    }
                ]
            },
            "bbox": [
                179,
                90,
                400,
                105
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msgp 存放欲发送消息内容的消息缓冲区指针 "
                    }
                ]
            },
            "bbox": [
                179,
                111,
                557,
                127
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msgsz 消息正文(而非整个消息结构)的长度"
                    }
                ]
            },
            "bbox": [
                179,
                133,
                541,
                149
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msgflg： 0 —消息队列满时，msgsnd 将会阻塞"
                    }
                ]
            },
            "bbox": [
                179,
                154,
                685,
                168
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "IPC_NOWAIT ——消息队列满时，msgsnd 立即返回-1"
                    }
                ]
            },
            "bbox": [
                287,
                175,
                694,
                191
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "MSG_NOERROR——消息正文长度超过 msgsz字节时，不报错，而是直接截去其中多余的部分，并只将前面的 msgsz字节发送出去"
                    }
                ]
            },
            "bbox": [
                144,
                197,
                848,
                233
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "功能： 在标识数为 msqid 的消息队列中添加一个消息，即向标识数为 msqid 的消息队列发送一个消息。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "返回值： 消息发送成功，返回0；否则返回-1，同时error中存有错误代码"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "错误代码：EAGAIN ——参数 msgflg 设为 IPC_NOWAIT，而消息队列已满"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                239,
                848,
                319
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EACCESS——无权限写入消息队列"
                    }
                ]
            },
            "bbox": [
                179,
                325,
                442,
                340
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EFAULT ——参数 msgp 指向的地址无法访问"
                    }
                ]
            },
            "bbox": [
                179,
                346,
                522,
                362
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EIDRM 标识符为 msqid的消息队列已被删除"
                    }
                ]
            },
            "bbox": [
                179,
                368,
                566,
                382
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EINTR —— 队列已满而处于阻塞的情况下，被信号唤醒"
                    }
                ]
            },
            "bbox": [
                179,
                388,
                618,
                404
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EINVAL ——无效的参数msqid、或消息类型 type小于等于 0、或 msgsz为负数或超过 系统限制值 MSGMAX "
                    }
                ]
            },
            "bbox": [
                146,
                410,
                848,
                445
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "ENOMEM ——系统无足够内存空间存放 msgbuf消息的副本"
                    }
                ]
            },
            "bbox": [
                179,
                453,
                628,
                469
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（3）msgrcv 系统调用"
                    }
                ],
                "level": 1
            },
            "bbox": [
                154,
                475,
                324,
                489
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\textcircled{1}"
                    },
                    {
                        "type": "text",
                        "content": "函数原型："
                    }
                ]
            },
            "bbox": [
                181,
                495,
                280,
                511
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "include <sys/types.h> #include <sys/ipc.h> #include <sys msg.h> ssize_t msgcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg); "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                144,
                519,
                848,
                619
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\textcircled{2}"
                    },
                    {
                        "type": "text",
                        "content": "参数:"
                    }
                ]
            },
            "bbox": [
                181,
                625,
                245,
                639
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msqid 消息队列的标识数"
                    }
                ]
            },
            "bbox": [
                179,
                646,
                398,
                661
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msgp 存放欲接收消息内容的消息缓冲区指针 "
                    }
                ]
            },
            "bbox": [
                179,
                667,
                556,
                682
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msgsz 消息正文(而非整个消息结构)的长度"
                    }
                ]
            },
            "bbox": [
                179,
                689,
                539,
                703
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msg-typ 0 接收消息队列中的第一个消息"
                    }
                ]
            },
            "bbox": [
                181,
                709,
                628,
                725
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\mathrm { > 0 }"
                    },
                    {
                        "type": "text",
                        "content": "接收第一个类型为 msgtyp的消息"
                    }
                ]
            },
            "bbox": [
                252,
                732,
                653,
                746
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "<0 接收第一个类型小于等于 msgtyp的绝对值的消息"
                    }
                ]
            },
            "bbox": [
                252,
                753,
                776,
                768
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msgflg 0 没有可以接收的消息时，msgrcv 阻塞"
                    }
                ]
            },
            "bbox": [
                181,
                775,
                685,
                789
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "IPC_NOWAIT ——没有可以接收的消息时，立即返回-1"
                    }
                ]
            },
            "bbox": [
                252,
                795,
                670,
                810
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "MSG_EXCEPT ——返回第一个类型不为 msgtyp 的消息"
                    }
                ]
            },
            "bbox": [
                250,
                816,
                662,
                832
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "MSG_NOERROR——消息正文长度超过 msgsz字节时，将直接截去其中多余的部分"
                    }
                ]
            },
            "bbox": [
                146,
                838,
                848,
                873
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\textcircled{3}"
                    },
                    {
                        "type": "text",
                        "content": "功能： 如果传递给参数 msgflg的值为 IPC_NOWAIT，并且没有可取的消息，那么"
                    }
                ]
            },
            "bbox": [
                179,
                879,
                848,
                896
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "给调用进程返回ENOMSG错误码，否则，调用进程阻塞，直到一条满足要求的消息到达消息队列。如果进程正在等待消息，而相应的消息队列被删除，则返回 EIDRM。如果当进程正在等待消息时，捕获到了一个信号，则返回 EINTR"
                    }
                ]
            },
            "bbox": [
                144,
                90,
                848,
                148
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "返回值： 接收成功，返回实际接收到的消息正文的字节数；否则返回-1，同时error中存有错误代码"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "错误代码：E2BIG ——消息长度超过 msgsz，且 MSG_NOERROR 标志没被使用"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                154,
                848,
                212
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EACCESS——无权限读取消息队列"
                    }
                ]
            },
            "bbox": [
                179,
                218,
                442,
                233
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EFAULT ——参数 msgp 指向的地址无法访问"
                    }
                ]
            },
            "bbox": [
                179,
                240,
                522,
                255
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EIDRM 标识符为 msqid 的消息队列已被删除"
                    }
                ]
            },
            "bbox": [
                179,
                261,
                564,
                275
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EINTR 等待消息的情况下，被信号唤醒"
                    }
                ]
            },
            "bbox": [
                179,
                282,
                532,
                298
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EINVAL ——无效的参数 msqid、或 msgsz 为负数"
                    }
                ]
            },
            "bbox": [
                179,
                304,
                561,
                319
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "ENOMSG ——参数 msgflg 设为 IPC_NOWAIT，但无满足要求的消息可接收"
                    }
                ]
            },
            "bbox": [
                179,
                325,
                737,
                340
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（4）msgctl 系统调用"
                    }
                ],
                "level": 1
            },
            "bbox": [
                154,
                347,
                324,
                361
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\textcircled{1}"
                    },
                    {
                        "type": "text",
                        "content": "函数原型："
                    }
                ]
            },
            "bbox": [
                181,
                368,
                280,
                382
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#include <sys/types.h> "
                    }
                ]
            },
            "bbox": [
                179,
                390,
                381,
                405
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#include <sys/ipc.h> "
                    }
                ]
            },
            "bbox": [
                179,
                411,
                363,
                426
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#include <sys/msg.h>"
                    }
                ]
            },
            "bbox": [
                179,
                432,
                363,
                448
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "int msgctl(int msqid, int cmd, struct msqid_ds *buf);"
                    }
                ]
            },
            "bbox": [
                181,
                454,
                652,
                469
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\textcircled{2}"
                    },
                    {
                        "type": "text",
                        "content": "参数:"
                    }
                ]
            },
            "bbox": [
                181,
                475,
                245,
                489
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msqid 消息队列的标识数"
                    }
                ]
            },
            "bbox": [
                179,
                495,
                398,
                511
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "cmd IPC_STAT ——将对应消息队列结构体的值复制到一份到buf所"
                    }
                ]
            },
            "bbox": [
                179,
                517,
                707,
                533
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "指的结构体中，调用者必须有读消息队列的权限"
                    }
                ]
            },
            "bbox": [
                179,
                539,
                557,
                554
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "IPC_SET —— 将 buf 所指结构体中的部分信息:"
                    }
                ]
            },
            "bbox": [
                250,
                560,
                626,
                576
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "msg_perm.uid,msg_perm.gid,mst_perm.mode,msg_qbytes 写到消息队列结构体中，并且更新消息队列结构体 msg_ctime成员的值。调用者必须有相应的权限。"
                    }
                ]
            },
            "bbox": [
                146,
                582,
                843,
                618
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "IPC_RMD 删除消息队列，并唤醒该消息队列上等待读或等待写的进程。调用者必须有相应的权限。"
                    }
                ]
            },
            "bbox": [
                144,
                624,
                847,
                659
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "功能： 获取或设置消息队列的属性信息，或者删除消息队列"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "返回值： 成功，返回0；否则返回-1，同时 error中存有错误代码"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "错误代码：EACCESS—— cmd 为 IPC_STAT，但调用进程无读消息队列的权限"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                179,
                667,
                786,
                725
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EFAULT —— 参数 cmd 为 IPC_STAT 或 IPC_SET ，但 buf 指向的地址无法访问"
                    }
                ]
            },
            "bbox": [
                179,
                731,
                781,
                747
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EIDRM 标识符为 msqid的消息队列已被删除"
                    }
                ]
            },
            "bbox": [
                179,
                753,
                566,
                768
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EINTR 等待消息的情况下，被信号唤醒"
                    }
                ]
            },
            "bbox": [
                179,
                774,
                531,
                789
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EINVAL — cmd 或 msqid 为无效的参数"
                    }
                ]
            },
            "bbox": [
                179,
                796,
                492,
                810
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EPERM —— 参数 cmd 为 IPC_RMD 或 IPC_SET ，但调用进程无足够的权限"
                    }
                ]
            },
            "bbox": [
                179,
                816,
                746,
                832
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4.5 linux 共享内存通信"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                858,
                465,
                878
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "共享内存是Linux 支持的三种进程间通信机制（IPC）中的一种。它实际上是一段特殊的内存区域。这一段内存区域可以被两个或者两个以上的进程映射到自身的地址空间中。一个进程写入共享内存中的信息，可以被其它使用这些共享内存的进程，通过一个简单点的内存读操作（memory read operation）读出，从而实现了进程间的通信。共享一个或多个进程通过同时出现在它们的虚拟地址空间的内存进程通信。这块虚拟内存的页面在每一个共享进程的页表中都有页表项目引用。但是不需要在所有进程的虚拟内存都有相同的地址。"
                    }
                ]
            },
            "bbox": [
                144,
                90,
                852,
                212
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. 共享内存的系统调用"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                214,
                381,
                229
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "任何Linux进程创建时，都有很大的虚拟地址空间，这块虚拟地址空间只有一部分放着代码、数据、堆和堆栈，剩余的那些部分在初始化时是空闲的。一块共享内存一旦被连接（attach），即会被映射入空闲的虚拟地址空间。随后，进程即可像对待普通的内存区域那样读、写共享内存。共享内存一共有四个系统调用，它们分别是："
                    }
                ]
            },
            "bbox": [
                144,
                237,
                853,
                317
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "shmget（）创建一块共享内存。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "shmat（）将一块已存在共享内存映射（map）到一个进程的地址空间。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "shmdt（）取消一个进程的地址空间中一块共享内存块的映射（unmap）。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "shmctl（）是管理共享内存的函数，用于执行对共享内存的各种控制命令。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                186,
                321,
                791,
                405
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（1） shmget ()：分配一块共享内存"
                    }
                ],
                "level": 1
            },
            "bbox": [
                184,
                413,
                472,
                429
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "函数声明："
                    }
                ]
            },
            "bbox": [
                186,
                436,
                304,
                451
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "include<sys/ipc.h>   \n#include<sys/shm.h>   \nint shmget(key_t,int size,int shmflg); "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                218,
                460,
                497,
                521
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "输入参数："
                    }
                ]
            },
            "bbox": [
                186,
                529,
                302,
                544
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "key:标识共享内存的键值，在调用前应赋初值"
                    }
                ]
            },
            "bbox": [
                218,
                552,
                606,
                568
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Size:所需的共享内存的最小尺寸（以字节为单位）"
                    }
                ]
            },
            "bbox": [
                218,
                575,
                606,
                590
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "shmflg:将分配的共享内存属性标志"
                    }
                ]
            },
            "bbox": [
                220,
                598,
                492,
                614
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "返回值："
                    }
                ]
            },
            "bbox": [
                186,
                621,
                285,
                636
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "若成功，则返回共享内存的标识符；否则返回-1，错误原因存在于errno中。"
                    }
                ]
            },
            "bbox": [
                218,
                644,
                806,
                659
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "errno=EINVAL：参数 size 小于 SHMMIN 或者大于 SHMMAX。"
                    }
                ]
            },
            "bbox": [
                218,
                668,
                704,
                683
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EEXIST：欲建立 key所指的共享内存，但已经存在。"
                    }
                ]
            },
            "bbox": [
                218,
                690,
                633,
                706
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EIDRM：参数 key所指的共享内存已经删除。"
                    }
                ]
            },
            "bbox": [
                220,
                714,
                571,
                728
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "ENOSPC：已经超过系统允许建立的共享内存的最大值（SHMALL）。"
                    }
                ]
            },
            "bbox": [
                218,
                738,
                752,
                753
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "ENOENT：参数 key 所指的共享内存不存在，参数 shmflg 也未设 IPC_CREAT 位。"
                    }
                ]
            },
            "bbox": [
                218,
                760,
                836,
                777
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EACCESS：没有权限。"
                    }
                ]
            },
            "bbox": [
                220,
                784,
                400,
                799
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "ENOMEM：核心内存不足。"
                    }
                ]
            },
            "bbox": [
                220,
                807,
                435,
                822
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "说明："
                    }
                ]
            },
            "bbox": [
                186,
                829,
                267,
                845
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "参数key的取值可以是一块已经存在的共享内存的键值、0、或IPC_PRIVATE。如果key的取值为IPC_PRIVATE，则函数shmget()将创建一块新的共享内存；如果 key 的取值为 0，"
                    }
                ]
            },
            "bbox": [
                144,
                854,
                850,
                892
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "而参数shmflg中设置了IPC_CREATE这标志，则同样将创建一块新的共享内存。在 IPC的通信模式下，不管是使用消息队列或者是共享内存，甚至是信号量，每个 IPC的对象都有唯一的名字，它被称做“键”（key）。"
                    }
                ]
            },
            "bbox": [
                144,
                90,
                852,
                149
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "参数size是要建立的共享内存的长度。所有的内存分配都是以页为单位的。"
                    }
                ]
            },
            "bbox": [
                179,
                154,
                769,
                171
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "参数shmflg主要和一些标志有关。其中有效的标志包括 IPC_CREAT和 IPC_EXCL，它们的功能与 open(2)的 O_CREAT 和 O_EXCL 相当。"
                    }
                ]
            },
            "bbox": [
                144,
                175,
                850,
                212
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在Linux内核中，每一个新创建的共享内存都由一个 shmid_ds的数据结构表示。如果函数 shmget( )成功创建了一块共享内存，则返回一个可以用于引用该共享内存的 shmid_ds数据结构的标识符。"
                    }
                ]
            },
            "bbox": [
                144,
                218,
                850,
                275
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "每一个IPC对象，系统共用一个 struct ipc_perm的数据结构来存放权限信息，以确定一个 ipc 操作是否可以访问该 IPC 对象。"
                    }
                ]
            },
            "bbox": [
                144,
                282,
                850,
                319
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（2） shmat()：连接（attach）一块共享内存"
                    }
                ],
                "level": 1
            },
            "bbox": [
                184,
                323,
                542,
                338
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "函数声明："
                    }
                ]
            },
            "bbox": [
                186,
                347,
                304,
                361
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "include<sys/ipc.h>   \n#include<sys/shm.h>   \nvoid \\*shmat(int shmid, const void \\*shmaddr,int shmgflg); "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                218,
                370,
                640,
                432
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "输入参数："
                    }
                ]
            },
            "bbox": [
                186,
                439,
                302,
                454
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "shmid:欲连接（attach）的共享内存的标识符。"
                    }
                ]
            },
            "bbox": [
                218,
                462,
                571,
                478
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "shmaddr: 欲连接（attach）的地址。"
                    }
                ]
            },
            "bbox": [
                220,
                486,
                490,
                500
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "shmflg:一个标识符。"
                    }
                ]
            },
            "bbox": [
                220,
                508,
                374,
                524
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "返回值："
                    }
                ]
            },
            "bbox": [
                186,
                532,
                285,
                546
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "若成功则返回已连接好的地址，否则返回-1，错误原因存在于errno。"
                    }
                ]
            },
            "bbox": [
                218,
                555,
                749,
                571
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "errno=EINVAL：参数 shmid 无效；参数 shmaddr 并非页对齐（page aligned），而参数 shmflg 中并未设置 SHM_RND 这个标志位。"
                    }
                ]
            },
            "bbox": [
                218,
                577,
                847,
                617
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "ENOMEN：分配标识符或页表时，系统内存不足。"
                    }
                ]
            },
            "bbox": [
                220,
                624,
                608,
                640
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EACCESS：调用进程没有权限以指定的方式连接该共享内存。"
                    }
                ]
            },
            "bbox": [
                220,
                646,
                699,
                663
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "说明："
                    }
                ]
            },
            "bbox": [
                186,
                671,
                267,
                684
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "函数shmat（）将以参数 shmid为标识符的共享内存连接（attach）到调用进程的数据段，连接的地址由shmaddr 指定。"
                    }
                ]
            },
            "bbox": [
                144,
                696,
                848,
                733
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "参数 shmflg 除了可以设置 SHM_RND 标志位外，还可以设置 SHM_RDONLY 标志位。"
                    }
                ]
            },
            "bbox": [
                179,
                738,
                793,
                753
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（3） shmdt()：断开（detach）一块共享内存的连接"
                    }
                ],
                "level": 1
            },
            "bbox": [
                184,
                758,
                600,
                774
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "函数声明："
                    }
                ]
            },
            "bbox": [
                186,
                781,
                304,
                796
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "include<sys/ipc.h> #include<sys/shm.h> int shmdt(const void \\*shmaddr); "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                220,
                804,
                473,
                866
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "输入参数："
                    }
                ]
            },
            "bbox": [
                186,
                873,
                302,
                889
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "shmaddr：欲断开连接（detach）的共享内存的虚拟地址。"
                    }
                ]
            },
            "bbox": [
                220,
                897,
                658,
                913
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "返回值："
                    }
                ],
                "level": 1
            },
            "bbox": [
                186,
                87,
                285,
                103
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "若成功则返回已连接好的地址，否则返回-1，错误原因存在于 errno 中。"
                    }
                ]
            },
            "bbox": [
                179,
                112,
                741,
                128
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "errno=EINVAL：参数 shmaddr 无效或参数 shmaddr 地址并非共享内存地址。"
                    }
                ]
            },
            "bbox": [
                179,
                135,
                759,
                149
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "说明："
                    }
                ]
            },
            "bbox": [
                181,
                156,
                230,
                171
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "函数shmdt 从调用进程的数据段，断开地址在shmaddr的共享内存。要分离的共享内存必须是当前连接到调用进程地址空间的共享内存质疑，也就是说shmaddr 必须等于连接某个共享内存时调用 shmat时的返回值。"
                    }
                ]
            },
            "bbox": [
                144,
                177,
                848,
                235
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（4） shmctl()：对一块共享内存的控制操作"
                    }
                ],
                "level": 1
            },
            "bbox": [
                184,
                240,
                534,
                255
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "函数声明："
                    }
                ]
            },
            "bbox": [
                186,
                261,
                304,
                275
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#include<sys/ipc.h> "
                    }
                ]
            },
            "bbox": [
                218,
                282,
                371,
                297
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "#include<sys/shm.h> "
                    }
                ]
            },
            "bbox": [
                220,
                305,
                378,
                319
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "int shmctl (int shmid, int cmd, struct shmid_ds *buff); "
                    }
                ]
            },
            "bbox": [
                218,
                329,
                608,
                343
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "输入参数："
                    }
                ]
            },
            "bbox": [
                186,
                349,
                302,
                363
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "shmid：为欲处理的共享内存的标识符。"
                    }
                ]
            },
            "bbox": [
                218,
                367,
                524,
                382
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "cmd：为欲进行的操作。"
                    }
                ]
            },
            "bbox": [
                220,
                386,
                405,
                400
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "buf：缓存。"
                    }
                ]
            },
            "bbox": [
                220,
                405,
                310,
                419
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "返回值："
                    }
                ]
            },
            "bbox": [
                186,
                423,
                285,
                437
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "若成功则返回共享内存的标识符，否则返回-1，错误原因存在于 errno 中。"
                    }
                ]
            },
            "bbox": [
                218,
                441,
                788,
                456
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "errno "
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\llcorner"
                    },
                    {
                        "type": "text",
                        "content": "EINVAL：参数 shmid 是个无效的标识符或 cmd 为无效命令。"
                    }
                ]
            },
            "bbox": [
                220,
                460,
                739,
                475
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EFAULT：参数 cmd 为 IPC_SET 或 IPC_STAT，但是参数 buf 却指向无效的地址。"
                    }
                ]
            },
            "bbox": [
                273,
                478,
                771,
                512
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EIDRM：参数shmid所指的共享内存已经删除。"
                    }
                ]
            },
            "bbox": [
                273,
                514,
                643,
                530
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EPERM：参数 cmd 为 IPC_SET 或 IPC_RMID，但是调用进程并不是创建者，所有者或超级用户，并且调用进程没有授予这些组或域的权限。"
                    }
                ]
            },
            "bbox": [
                273,
                533,
                773,
                586
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "EACCESS：参数cmd 为 IPC_STAT，但是没有权限读写该共享内存。"
                    }
                ]
            },
            "bbox": [
                273,
                589,
                801,
                605
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "说明"
                    }
                ],
                "level": 1
            },
            "bbox": [
                186,
                608,
                262,
                623
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "该系统调用允许用户得到一块共享内存的相关信息，设置一块共享内存的所有者，组以及读写权限，或者销毁一块共享内存。以shmid为标识符的共享内存的相关信息将被放在一个shmid_ds的数据结构体中返回。"
                    }
                ]
            },
            "bbox": [
                144,
                630,
                848,
                688
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "实验五 简单文件系统的实现"
                    }
                ],
                "level": 1
            },
            "bbox": [
                305,
                733,
                705,
                758
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5.1 设计目的和内容要求"
                    }
                ],
                "level": 1
            },
            "bbox": [
                191,
                789,
                458,
                809
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1. 设计目的"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                845,
                284,
                860
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "通过具体的文件存储空间的管理、文件的物理结构、目录结构和文件操作的实现，加深"
                    }
                ]
            },
            "bbox": [
                179,
                876,
                848,
                892
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "对文件系统内部数据结构、功能以及实现过程的理解。"
                    }
                ]
            },
            "bbox": [
                144,
                90,
                564,
                105
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2．内容要求"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                116,
                285,
                131
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "(1)在内存中开辟一个虚拟磁盘空间作为文件存储分区，在其上实现一个简单的基于多级目录的单用户单任务系统中的文件系统。在退出该文件系统的使用时，应将该虚拟文件系统以一个文件的方式保存到磁盘上，以便下次可以再将它恢复到内存的虚拟磁盘空间中。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "(2)文件存储空间的分配可采用显式链接分配或其他的办法。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "(3)空闲磁盘空间的管理可选择位示图或其他的办法。如果采用位示图来管理文件存储空间，并采用显式链接分配方式，那么可以将位示图合并到 FAT中。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "(4)文件目录结构采用多级目录结构。为了简单起见，可以不使用索引结点，其中的每个目录项应包含文件名、物理地址、长度等信息，还可以通过目录项实现对文件的读和写的保护。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "(5)要求提供以下操作命令："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                143,
                852,
                326
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": " my_format：对文件存储器进行格式化，即按照文件系统的结构对虚拟磁盘空间进行布局，并在其上创建根目录以及用于管理文件存储空间等的数据结构。"
                    }
                ]
            },
            "bbox": [
                179,
                330,
                850,
                363
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "my_mkdir：用于创建子目录。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "my_rmdir：用于删除子目录。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "my_ls：用于显示目录中的内容。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "my_cd：用于更改当前目录。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "my_create：用于创建文件。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "my_open：用于打开文件。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "my_close：用于关闭文件。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "my_write：用于写文件。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "my_read：用于读文件。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "my_rm：用于删除文件。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "my_exitsys：用于退出文件系统。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                216,
                367,
                505,
                568
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3．学时安排（12 学时）"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                580,
                369,
                595
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4． 开发平台"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                617,
                292,
                632
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "Linux 环境，gcc，gdb，vim 或 gedit 等。"
                    }
                ]
            },
            "bbox": [
                179,
                645,
                485,
                661
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5．思考"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                671,
                250,
                687
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "(1)我们的数据结构中的文件物理地址信息是使用 C 语言的指针类型、还是整型，为什么？"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "(2)如果引入磁盘索引结点，上述实现过程需要作哪些修改？"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "(3)如果设计的是一个单用户多任务文件系统，则系统需要进行哪些扩充（尤其要考虑读写指针问题）？如果设计的是一个多用户文件系统，则又要进行哪些扩充？"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                700,
                850,
                790
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5.2 预备知识 "
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                809,
                294,
                825
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5.2.1 FAT 文件系统介绍"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                853,
                415,
                869
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1．概述"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                891,
                250,
                906
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "FAT文件系统是微软公司在其早期的操作系统MS-DOS及Windows9x中采用的文件系统，它被设计用来管理小容量的磁盘空间。FAT文件系统是以他的文件组织方式——文件分配表（file allocation table，FAT）命名的，文件分配表的每个表项中存放某文件的下一个盘块号，而该文件的起始盘块号则保存在它的文件控制块 FCB中。在文件分配表中，一般用FFFF来标识文件的结束；用 0000来标识某个逻辑块未被分配，即是空闲块。为了提高文件系统的可靠性，在逻辑磁盘上通常设置两张文件分配表，它们互为备份。此外，文件分配表必须存放在逻辑磁盘上的固定位置，而根目录区通常位于 FAT2之后，以便操作系统在启动时能够定位所需的文件，其磁盘布局如图3-1所示："
                    }
                ]
            },
            "bbox": [
                144,
                90,
                852,
                254
            ]
        },
        {
            "type": "table",
            "content": {
                "image_source": {
                    "path": "images/fa8c75bfbf6febaed460ddd9ce00151034952a82b7364ccd37d3153c0c5f8433.jpg"
                },
                "table_caption": [],
                "table_footnote": [],
                "html": "<table><tr><td>引导块</td><td>FAT1</td><td>FAT2</td><td>根目录区</td><td>数据区</td></tr></table>",
                "table_type": "simple_table",
                "table_nest_level": 1
            },
            "bbox": [
                184,
                256,
                724,
                292
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "图 5-1 FAT文件系统磁盘布局"
                    }
                ]
            },
            "bbox": [
                295,
                298,
                532,
                313
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "上述磁盘布局中，引导块中主要存放了用于描述分区的各种信息，包括逻辑块的大小、文件分配表的大小及位置、根目录的大小及位置等。除此之外，用于加载操作系统内核的引导程序也存储在引导块中。"
                    }
                ]
            },
            "bbox": [
                146,
                319,
                850,
                379
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "FAT 文件系统家族又分为FAT12、FAT16、FAT32三种类型，这里的数字表示文件分配表中每个表项（即簇号）所占的位数，即FAT12中每个表项占 1.5个字节（12位），FAT16中每个表项占2个字节（16位），FAT32中每个表项占 4个字节（32 位）。由于 FAT文件系统是以簇为单位为文件分配磁盘空间的（一个簇是一组连续的扇区，通常包含 "
                    },
                    {
                        "type": "equation_inline",
                        "content": "2 ^ { \\mathfrak { n } }"
                    },
                    {
                        "type": "text",
                        "content": "个扇区），因此，FAT32比FAT12 和FAT16支持更多的簇数、更小的簇大小和更大的磁盘容量，从而大大提高磁盘空间的利用率。通常，FAT12适用于小容量磁盘，如软盘；FAT16是 MS-DOS的文件系统；FAT32是 Windows9x 中的主要文件系统，开始支持大容量磁盘。"
                    }
                ]
            },
            "bbox": [
                144,
                382,
                853,
                527
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2．文件控制块FCB"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                538,
                334,
                554
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "为了正确、方便地操作文件，必须设置相应的数据结构用于存放文件的描述和控制信息，常用的数据结构有文件控制块（简称FCB）和索引节点（简称 i节点）。在 FAT文件系统中使用文件控制块。文件与文件控制块一一对应，而文件控制块的有序集合就称为文件目录，即一个文件控制块就是一个文件目录项。"
                    }
                ]
            },
            "bbox": [
                144,
                570,
                848,
                649
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "虽然不同文件系统的文件控制块的内容和格式不完全相同，但通常都包括以下三类信息：基本信息、存取控制信息和使用信息。"
                    }
                ]
            },
            "bbox": [
                144,
                652,
                855,
                686
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）基本信息。包括文件名、用户名、文件类型、文件的物理地址、文件长度、文件的逻辑结构和物理结构等。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）存取控制信息。一般分别给出文件主、伙伴用户、一般用户的存取权限。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）使用信息。包括文件的建立日期及时间、上次存取文件的日期及时间、当前的使用信息等。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                689,
                850,
                778
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "以MS-DOS（使用 FAT16文件系统）为例，它的每个文件控制块包括32个字节，其字节分配情况如图3-2所示："
                    }
                ]
            },
            "bbox": [
                144,
                781,
                850,
                815
            ]
        },
        {
            "type": "table",
            "content": {
                "image_source": {
                    "path": "images/6af0a7aec88b437dc381f3b39b135df7126b563e642ffa373b2993c72cae56bc.jpg"
                },
                "table_caption": [],
                "table_footnote": [],
                "html": "<table><tr><td colspan=\"8\">字节 8B 3B 1B 10B 2B 2B 2B 4B</td></tr><tr><td>文件名</td><td>扩展名</td><td>属性</td><td>保留</td><td>时间</td><td>日期</td><td>首块号</td><td>大小</td></tr></table>",
                "table_type": "complex_table",
                "table_nest_level": 1
            },
            "bbox": [
                188,
                819,
                673,
                872
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "图 5-2 MS-DOS 的文件控制块"
                    }
                ]
            },
            "bbox": [
                277,
                873,
                505,
                889
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "其中属性字段占一个字节，它的每一位用来表示该文件是否具有某种属性，如果某一位"
                    }
                ]
            },
            "bbox": [
                181,
                892,
                850,
                909
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "的值为 1，则表示该文件具有该属性。各位所表示的属性如表 3-1 所示："
                    }
                ]
            },
            "bbox": [
                144,
                85,
                700,
                101
            ]
        },
        {
            "type": "table",
            "content": {
                "image_source": {
                    "path": "images/7984fb35be11dd335935b4ebdd2f35eb4e11f76ebc6d13e2b6b3e25ca7e6eb5d.jpg"
                },
                "table_caption": [
                    {
                        "type": "text",
                        "content": "表5-1 文件属性对照表"
                    }
                ],
                "table_footnote": [],
                "html": "<table><tr><td>位</td><td>7</td><td>6</td><td>5</td><td>4</td><td>3</td><td>2</td><td>1</td><td>0</td></tr><tr><td>属性</td><td>保留</td><td>保留</td><td>存档</td><td>子目录</td><td>卷标</td><td>系统文件</td><td>隐藏</td><td>只读</td></tr></table>",
                "table_type": "simple_table",
                "table_nest_level": 1
            },
            "bbox": [
                176,
                120,
                803,
                162
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3．根目录区"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                189,
                284,
                205
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "FAT12、FAT16的根目录区是固定区域、固定大小的，位于第二个 FAT之后，如图 3-1所示，且占据若干连续扇区，其中 FAT12占14个扇区，一共 224个根目录项；而 FAT16占32个扇区，最多保存512个目录项，作为系统区的一部分。FAT32的根目录是作为文件处理的，采用与子目录文件相同的管理方式，其位置不是固定的，不过一般情况也是位于第二个FAT之后的，其大小可视需要增加，因此根目录下的文件数目不再受最多512 个的限制。"
                    }
                ]
            },
            "bbox": [
                144,
                221,
                847,
                323
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5.2.2 几个 C 语言库函数介绍 "
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                332,
                460,
                349
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "由于我们的文件系统是建立在内存的虚拟磁盘上的，在退出文件系统的时候必须以一个文件的形式保存到磁盘上；而在启动文件系统的时候必须从磁盘上将该文件读入到内存的虚拟磁盘中。下面介绍几个可能会用到的C库函数，在使用这些库函数之前必须包含头文件“stdio.h”。"
                    }
                ]
            },
            "bbox": [
                144,
                365,
                848,
                444
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1．打开文件函数 fopen()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                456,
                384,
                472
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）格式：FILE *fopen(const char *filename,const char *mode)"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）功能：按照指定打开方式打开指定文件。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）输入参数说明："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                488,
                721,
                546
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "filename：待打开的文件名，如果不存在就创建该文件。"
                    }
                ]
            },
            "bbox": [
                189,
                552,
                626,
                568
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "mode： 文件打开方式，常用的有："
                    }
                ]
            },
            "bbox": [
                189,
                574,
                467,
                588
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\" \\mathrm { r } ^ { \\prime \\prime }"
                            },
                            {
                                "type": "text",
                                "content": "：为读而打开文本文件（不存在则出错）。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": " "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\" \\mathrm { w } ^ { \\prime \\prime }"
                            },
                            {
                                "type": "text",
                                "content": "：为写而打开文本文件（若不存在则创建该文件；反之，则从文件起始位置写,原内容将被覆盖）。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": " "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\mathrm { ^ { \\prime \\prime } a ^ { \\prime \\prime } }"
                            },
                            {
                                "type": "text",
                                "content": "：为在文件末尾添加数据而打开文本文件。（若不存在则创建该文件；反之,在原文件末尾追加）。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": " "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\" { \\mathrm { r } } + \""
                            },
                            {
                                "type": "text",
                                "content": "：为读和写而打开文本文件。（读时，从头开始；在写数据时,新数据只覆盖所占的空间，其后不变) 。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": " "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\" _ { \\mathbb { W } ^ { + } } \\prime \\prime"
                            },
                            {
                                "type": "text",
                                "content": "：首先建立一个新文件，进行写操作，随后可以从头开始读。(若文件存在，原内容将全部消失) 。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\mathrm { ^ { \\prime \\prime } a } + \\mathrm { ^ { \\prime \\prime } }"
                            },
                            {
                                "type": "text",
                                "content": "：功能与\"a\"相同；只是在文件末尾添加新的数据后，可以从头开始读。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                590,
                847,
                772
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "另外，上述模式字符串中都可以加一个“b”字符，如 rb、wb、ab、rb+、wb+、ab+等组合，字符“b”表示 fopen() 函数打开的文件为二进制文件，而非纯文字文件。"
                    }
                ]
            },
            "bbox": [
                144,
                780,
                843,
                816
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（4）输出：一个指向 FILE类型的指针。"
                    }
                ]
            },
            "bbox": [
                189,
                822,
                492,
                838
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2．关闭文件函数 fclose()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                848,
                393,
                865
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（1）格式：int fclose(FILE * stream);"
                    }
                ]
            },
            "bbox": [
                189,
                881,
                510,
                897
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（2）功能：用来关闭先前fopen()打开的一个文件。此动作会让缓冲区内的数据写入文件中，并释放系统所提供的文件资源。"
                    }
                ]
            },
            "bbox": [
                144,
                90,
                848,
                127
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（3）输入参数说明："
                    }
                ]
            },
            "bbox": [
                189,
                131,
                344,
                148
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "stream：指向要关闭文件的指针，它是先前执行fopen()函数的返回值。"
                    }
                ]
            },
            "bbox": [
                189,
                154,
                739,
                170
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（4）输出：若关闭文件成功则返回0；有错误发生时则返回EOF并把错误代码存到errno。"
                    }
                ]
            },
            "bbox": [
                189,
                175,
                836,
                191
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3．读文件函数 fread()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                202,
                366,
                218
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）格式：size_t fread( void *buffer, size_t size, size_t count, FILE *stream )；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）功能：读二进制文件到内存。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）输入参数说明："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                234,
                845,
                291
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "buffer：用于存放输入数据的缓冲区的首地址；"
                    }
                ]
            },
            "bbox": [
                189,
                298,
                554,
                313
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "stream：使用fopen()打开的文件的指针，用于指示要读取的文件；"
                    }
                ]
            },
            "bbox": [
                189,
                319,
                705,
                335
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "size： 每个数据块的字节数；"
                    }
                ]
            },
            "bbox": [
                191,
                341,
                431,
                356
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "count： 要读入的数据块的个数；"
                    }
                ]
            },
            "bbox": [
                191,
                363,
                448,
                376
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "size*count：表示要求读取的字节数。"
                    }
                ]
            },
            "bbox": [
                191,
                384,
                485,
                399
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（4）输出：实际读取的数据块的个数。"
                    }
                ]
            },
            "bbox": [
                191,
                405,
                485,
                420
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4．写文件函数 fwrite()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                431,
                374,
                447
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）格式：size_t fwite(const void *buffer,size_t size,size_t count,FILE*stream)；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）功能：将数据写到二进制文件中。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）输入参数说明："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                463,
                821,
                542
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "buffer：用于存放输出数据的缓冲区的首地址；"
                    }
                ]
            },
            "bbox": [
                189,
                548,
                554,
                564
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "stream：使用fopen()打开的文件的指针，用于指示要写出的文件；"
                    }
                ]
            },
            "bbox": [
                189,
                570,
                705,
                586
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "size： 每个数据块的字节数；"
                    }
                ]
            },
            "bbox": [
                191,
                592,
                431,
                606
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "count： 要写出的数据块的个数；"
                    }
                ]
            },
            "bbox": [
                191,
                613,
                448,
                627
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "size*count：表示要求写出的字符数。"
                    }
                ]
            },
            "bbox": [
                191,
                634,
                485,
                649
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（4）输出：实际写出的数据块的个数。"
                    }
                ]
            },
            "bbox": [
                189,
                656,
                484,
                671
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5．判断文件结束函数 feof ()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                682,
                420,
                697
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）格式：int feof(FILE * stream)"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）功能：用来判断是否已读取到文件末尾。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                191,
                714,
                539,
                750
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（3）输入参数说明："
                    }
                ]
            },
            "bbox": [
                191,
                757,
                344,
                772
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "stream：使用fopen()打开的文件的指针，用于指示要判断的文件。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）输出：如果已读到文件尾则返回非零值，其他情况返回 0。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                778,
                710,
                814
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "6．定位文件函数 fseek()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                826,
                384,
                841
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）格式：int fseek( FILE *stream, long offset, int origin )；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）功能： 移动文件读写指针在文件中的位置。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                859,
                729,
                895
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（3）输入参数说明："
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                90,
                342,
                104
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "stream：使用fopen()打开的文件的指针，用于指示要定位读写指针的文件；"
                    }
                ]
            },
            "bbox": [
                189,
                111,
                774,
                126
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "offset：位移量，以字节为单位；"
                    }
                ]
            },
            "bbox": [
                189,
                133,
                448,
                147
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "origin：初始位置，有三个常量："
                    }
                ]
            },
            "bbox": [
                189,
                154,
                448,
                168
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "SEEK_CUR：读写指针当前位置；"
                    }
                ]
            },
            "bbox": [
                250,
                175,
                492,
                190
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "SEEK_SET：文件开头；"
                    }
                ]
            },
            "bbox": [
                250,
                197,
                421,
                211
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "SEEK_END：文件末尾。"
                    }
                ]
            },
            "bbox": [
                250,
                219,
                421,
                233
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "当 origin 值为 SEEK_CUR 或 SEEK_END 时，参数 offset 可以为负值。"
                    }
                ]
            },
            "bbox": [
                189,
                252,
                717,
                268
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5.3 实例系统的设计与实现"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                287,
                394,
                302
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "本实例系统是仿照FAT16文件系统来设计实现的，但根目录没有采用FAT16的固定位置、固定大小的根目录区，而是以根目录文件的形式来实现的，这也是目前主流文件系统对根目录的处理方式。"
                    }
                ]
            },
            "bbox": [
                144,
                326,
                848,
                384
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5.3.1 数据结构设计"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                395,
                376,
                411
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1．需要包含的头文件"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                432,
                354,
                448
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）#include <stdio.h>"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）#include <malloc.h>"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）#include <string.h>"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）#include <time.h>"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                464,
                398,
                543
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2．定义的常量"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                555,
                302,
                570
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）#define BLOCKSIZE 1024 磁盘块大小"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）#define SIZE 1024000 虚拟磁盘空间大小 "
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）#define END 65535 FAT中的文件结束标志"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）#define FREE 0 FAT中盘块空闲标志"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）#define ROOTBLOCKNUM 2 根目录区所占盘块总数"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（6）#define MAXOPENFILE 10 最多同时打开文件个数"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                587,
                675,
                709
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3．数据结构"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                721,
                284,
                736
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（1）文件控制块 FCB"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                752,
                351,
                766
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "用于记录文件的描述和控制信息，每个文件设置一个 FCB，它也是文件的目录项的内容。"
                    }
                ]
            },
            "bbox": [
                181,
                774,
                847,
                789
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "typedef struct FCB //仿照 FAT16 设置的"
                    }
                ]
            },
            "bbox": [
                181,
                795,
                512,
                810
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "char filename[8]；//文件名  \nchar exname[3]；//文件扩展名  \nunsigned char attribute; //文件属性字段：为简单起见，我们只为文件设置"
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                184,
                818,
                823,
                897
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "//了两种属性：值为0时表示目录文件，值为1时表示数据文件  \nunsigned short time;//文件创建时间  \nunsigned short data;//文件创建日期  \nunsigned short first;//文件起始盘块号  \nunsigned long length;//文件长度（字节数）  \nchar free; //表示目录项是否为空，若值为0，表示空，值为1，表示已分配  \n}fcb;"
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                181,
                89,
                843,
                256
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（2）文件分配表 FAT"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                282,
                352,
                298
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在本实例中，文件分配表有两个作用：一是记录磁盘上每个文件所占据的磁盘块的块号；二是记录磁盘上哪些块已经分配出去了，哪些块是空闲的，即起到了位示图的作用。若FAT中某个表项的值为FREE，则表示该表项所对应的磁盘块是空闲的；若某个表项的值为 END，则表示所对应的磁盘块是某文件的最后一个磁盘块；若某个表项的值是其他值，则该值表示某文件的下一个磁盘块的块号。为了提高系统的可靠性，本实例中设置了两张 FAT表，它们互为备份，每个FAT占据两个磁盘块。"
                    }
                ]
            },
            "bbox": [
                144,
                303,
                852,
                426
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "typedef struct FAT  \n{ unsigned short id; }fat; "
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                181,
                432,
                379,
                512
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（3）用户打开文件表 USEROPEN"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                539,
                430,
                554
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "当打开一个文件时，必须将文件的目录项中的所有内容全部复制到内存中，同时还要记录有关文件操作的动态信息，如读写指针的值等。在本实例中实现的是一个用于单用户单任务系统的文件系统，为简单起见，我们把用户文件描述符表和内存 FCB表合在一起，称为用户打开文件表，表项数目为 10，即一个用户最多可同时打开 10 个文件。然后用一个数组来描述，则数组下标即某个打开文件的描述符。另外，我们在用户打开文件表中还设置了一个字段“char dir[80]”，用来记录每个打开文件所在的目录名，以方便用户打开不同目录下具有相同文件名的不同文件。"
                    }
                ]
            },
            "bbox": [
                144,
                558,
                852,
                705
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "typedef struct USEROPEN  \n{ char filename[8]; //文件名 char exname[3];//文件扩展名 unsigned char attribute;//文件属性：值为0时表示目录文件，值为1时表示数据文件"
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                144,
                709,
                848,
                832
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "unsigned short time; //文件创建时间  \nunsigned short data; //文件创建日期  \nunsigned short first; //文件起始盘块号"
                    }
                ],
                "code_language": "txt"
            },
            "bbox": [
                215,
                838,
                547,
                898
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "unsigned long length;//文件长度（对数据文件是字节数，对目录文件可以是目录项个数）"
                    }
                ]
            },
            "bbox": [
                144,
                90,
                845,
                126
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "char free；//表示目录项是否为空，若值为0，表示空，值为1，表示已分配//前面内容是文件的 FCB中的内容。"
                    }
                ]
            },
            "bbox": [
                213,
                131,
                821,
                170
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "// 下面设置的dirno和diroff记录了相应打开文件的目录项在父目录文件中的位置，//这样如果该文件的fcb 被修改了，则要写回父目录文件时比较方便"
                    }
                ]
            },
            "bbox": [
                213,
                175,
                847,
                212
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "int dirno; //相应打开文件的目录项在父目录文件中的盘块号"
                    }
                ]
            },
            "bbox": [
                216,
                218,
                715,
                233
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "int diroff;// 相应打开文件的目录项在父目录文件的dirno盘块中的目录项序号"
                    }
                ]
            },
            "bbox": [
                216,
                239,
                847,
                255
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "char dir[MAXOPENFILE][80]; //相应打开文件所在的目录名，这样方便快速检查出指定文件是否已经打开"
                    }
                ]
            },
            "bbox": [
                144,
                261,
                847,
                298
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "int count; //读写指针在文件中的位置"
                    }
                ]
            },
            "bbox": [
                216,
                304,
                532,
                319
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "char fcbstate; //是否修改了文件的 FCB 的内容，如果修改了置为 1，否则为 0"
                    }
                ]
            },
            "bbox": [
                213,
                325,
                840,
                341
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "char topenfile; //表示该用户打开表项是否为空，若值为0，表示为空，否则表示已被某打开文件占据"
                    }
                ]
            },
            "bbox": [
                144,
                346,
                847,
                382
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "}useropen; "
                    }
                ]
            },
            "bbox": [
                181,
                390,
                273,
                405
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "（4）引导块 BLOCK0"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                432,
                342,
                447
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "在引导块中主要存放逻辑磁盘的相关描述信息，比如磁盘块大小、磁盘块数量、文件分配表、根目录区、数据区在磁盘上的起始位置等。如果是引导盘，还要存放操作系统的引导信息。本实例是在内存的虚拟磁盘中创建一个文件系统，因此所包含的内容比较少，只有磁盘块大小、磁盘块数量、数据区开始位置、根目录文件开始位置等。"
                    }
                ]
            },
            "bbox": [
                144,
                453,
                848,
                533
            ]
        },
        {
            "type": "code",
            "content": {
                "code_caption": [],
                "code_content": [
                    {
                        "type": "text",
                        "content": "typedef struct BLOCK0 //引导块内容  \n{ //存储一些描述信息，如磁盘块大小、磁盘块数量、最多打开文件数等、char information[200]; unsigned short root; //根目录文件的起始盘块号 unsigned char *startblock; //虚拟磁盘上数据区开始位置}block0;"
                    }
                ],
                "code_language": "c"
            },
            "bbox": [
                181,
                539,
                776,
                683
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4．全局变量定义"
                    }
                ],
                "level": 1
            },
            "bbox": [
                215,
                715,
                354,
                730
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）unsigned char *myvhard： 指向虚拟磁盘的起始地址"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）useropen openfilelist[MAXOPENFILE]： 用户打开文件表数组"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）useropen *ptrcurdir： 指向用户打开文件表中的当前目录所在打开文件表项的位置；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）char currentdir[80]： 记录当前目录的目录名（包括目录的路径）"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）unsigned char* startp： 记录虚拟磁盘上数据区开始位置"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                747,
                847,
                869
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5．虚拟磁盘空间布局"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                879,
                354,
                896
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                620,
                61
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "由于真正的磁盘操作需要涉及到设备的驱动程序，所以本实例是在内存中申请一块空间作为虚拟磁盘使用，我们的文件系统就建立在这个虚拟磁盘上。虚拟磁盘一共划分成 1000个磁盘块，每个块1024个字节，其布局格式是模仿FAT文件系统设计的，其中引导块占一个盘块，两张FAT各占 2个盘块，剩下的空间全部是数据区，在对虚拟磁盘进行格式化的时候，将把数据区第1块（即虚拟磁盘的第 6 块）分配给根目录文件，如图3-3 所示："
                    }
                ]
            },
            "bbox": [
                144,
                90,
                850,
                191
            ]
        },
        {
            "type": "table",
            "content": {
                "image_source": {
                    "path": "images/dc336a5d1be7e2ccee3277b29a4afd7999c449358f141fe8629e52752ef9f5d4.jpg"
                },
                "table_caption": [],
                "table_footnote": [],
                "html": "<table><tr><td colspan=\"4\">块数 1块 2块 2块 995块</td></tr><tr><td>引导块</td><td>FAT1</td><td>FAT2</td><td>数据区</td></tr></table>",
                "table_type": "complex_table",
                "table_nest_level": 1
            },
            "bbox": [
                186,
                193,
                771,
                244
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "图5-3 虚拟磁盘空间布局"
                    }
                ]
            },
            "bbox": [
                321,
                253,
                527,
                268
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "当然，也可以仿照 FAT16文件系统，设置根目录区，其位置紧跟第2张 FAT 后面，大小也是固定的，这个思路相对要简单一点，请同学们自己去实现。"
                    }
                ]
            },
            "bbox": [
                146,
                274,
                850,
                311
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5.3.2 实例主要命令及函数设计"
                    }
                ],
                "level": 1
            },
            "bbox": [
                189,
                321,
                478,
                338
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "1．系统主函数 main()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                359,
                357,
                375
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）对应命令：无"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）命令调用格式：无"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）函数设计格式：void main()"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）功能：系统主函数"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）输入：无"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（6）输出：无"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（7）函数需完成的工作："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                391,
                448,
                533
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "对前面定义的全局变量进行初始化；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "调用 startsys()进入文件系统；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "列出文件系统提供的各项功能及命令调用格式；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "显示命令行提示符，等待用户输入命令；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "将用户输入的命令保存到一个 buf中；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{6}"
                            },
                            {
                                "type": "text",
                                "content": "对buf中的内容进行命令解析，并调用相应的函数执行用户键入的命令；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{7}"
                            },
                            {
                                "type": "text",
                                "content": "如果命令不是“my_exitsys”，则命令执行完毕后转 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                179,
                539,
                766,
                684
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "2. 进入文件系统函数 startsys()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                695,
                445,
                711
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）对应命令：无"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）命令调用格式：无"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）函数设计格式：void startsys()"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）功能：由main()函数调用，进入并初始化我们所建立的文件系统，以供用户使用。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）输入：无"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（6）输出：无。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（7）函数需完成的工作："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                727,
                836,
                870
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\textcircled{1}"
                    },
                    {
                        "type": "text",
                        "content": "申请虚拟磁盘空间；"
                    }
                ]
            },
            "bbox": [
                179,
                877,
                359,
                891
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "使用c语言的库函数fopen()打开myfsys文件：若文件存在，则转 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "；若文件不存在，则创建之，转 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "使用c语言的库函数fread()读入 myfsys 文件内容到用户空间中的一个缓冲区中，并判断其开始的8个字节内容是否为“10101010”（文件系统魔数），如果是，则转 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "；否则转 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "将上述缓冲区中的内容复制到内存中的虚拟磁盘空间中；转 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{7}"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "在屏幕上显示“myfsys文件系统不存在，现在开始创建文件系统”信息，并调用my_format()对 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "中申请到的虚拟磁盘空间进行格式化操作。转 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{6}"
                            },
                            {
                                "type": "text",
                                "content": "；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{6}"
                            },
                            {
                                "type": "text",
                                "content": "将虚拟磁盘中的内容保存到 myfsys 文件中；转 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{7}"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{7}"
                            },
                            {
                                "type": "text",
                                "content": "使用 c 语言的库函数 fclose()关闭 myfsys 文件；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{8}"
                            },
                            {
                                "type": "text",
                                "content": "初始化用户打开文件表，将表项 0分配给根目录文件使用，并填写根目录文件的相关信息，由于根目录没有上级目录，所以表项中的dirno和diroff分别置为5（根目录所在起始块号）和0；并将ptrcurdir指针指向该用户打开文件表项。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{9}"
                            },
                            {
                                "type": "text",
                                "content": "将当前目录设置为根目录。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                89,
                850,
                384
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "3．磁盘格式化函数 my_format()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                394,
                438,
                411
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）对应命令：my_format"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）命令调用格式：my_format"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）函数设计格式：void my_format()"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）功能：对虚拟磁盘进行格式化，布局虚拟磁盘，建立根目录文件（或根目录区）。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）输入：无"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（6）输出：无。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                188,
                426,
                838,
                548
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（7）函数需完成的工作："
                    }
                ]
            },
            "bbox": [
                189,
                555,
                379,
                570
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "将虚拟磁盘第一个块作为引导块，开始的 8个字节是文件系统的魔数，记为“10101010”；在之后写入文件系统的描述信息，如 FAT表大小及位置、根目录大小及位置、盘块大小、盘块数量、数据区开始位置等信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "在引导块后建立两张完全一样的 FAT表，用于记录文件所占据的磁盘块及管理虚拟磁盘块的分配，每个FAT占据两个磁盘块；对于每个 FAT中，前面5 个块设置为已分配，后面995个块设置为空闲；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "在第二张FAT 后创建根目录文件 root，将数据区的第 1 块（即虚拟磁盘的第 6 块）分配给根目录文件，在该磁盘上创建两个特殊的目录项：“.”和“..”，其内容除了文件名不同之外，其他字段完全相同。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                576,
                850,
                763
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "4．更改当前目录函数 my_cd()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                772,
                420,
                790
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）对应命令：my_cd"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）命令调用格式：my_cd dirname"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）函数设计格式：void my_cd(char *dirname)"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）功能：改变当前目录到指定的名为dirname 的目录。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）输入："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                806,
                626,
                906
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "dirname：新的当前目录的目录名；"
                    }
                ]
            },
            "bbox": [
                223,
                90,
                492,
                105
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（6）输出：无"
                    }
                ]
            },
            "bbox": [
                189,
                111,
                302,
                126
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（7）函数需完成的工作："
                    }
                ]
            },
            "bbox": [
                189,
                131,
                379,
                148
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "调用my_open()打开指定目录名的父目录文件，并调用do_read()读入该父目录文件内容到内存中；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "在父目录文件中检查新的当前目录名是否存在，如果存在则转 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "，否则返回，并显示出错信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "调用 my_close()关闭 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "中打开的父目录文件；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "调用my_close()关闭原当前目录文件；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "如果新的当前目录文件没有打开，则打开该目录文件；并将 ptrcurdir 指向该打开文件表项；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{6}"
                            },
                            {
                                "type": "text",
                                "content": "设置当前目录为该目录。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                154,
                847,
                340
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "5．创建子目录函数 my_mkdir()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                351,
                428,
                368
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）对应命令：my_mkdir"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）命令调用格式：my_ mkdir dirname"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）函数设计格式：void my_mkdir(char *dirname)"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）功能：在当前目录下创建名为 dirname 的子目录。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）输入："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                384,
                608,
                483
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "dirname：新建目录的目录名。"
                    }
                ]
            },
            "bbox": [
                225,
                491,
                458,
                505
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（6）输出：无。"
                    }
                ]
            },
            "bbox": [
                189,
                512,
                309,
                527
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（7）函数需完成的工作："
                    }
                ]
            },
            "bbox": [
                189,
                533,
                378,
                548
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "调用 do_read()读入当前目录文件内容到内存，检查当前目录下新建目录文件是否重名，若重名则返回，并显示错误信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "为新建子目录文件分配一个空闲打开文件表项，如果没有空闲表项则返回-1，并显示错误信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "检查FAT是否有空闲的盘块，如有则为新建目录文件分配一个盘块，否则释放 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "中分配的打开文件表项，返回，并显示错误信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "在当前目录中为新建目录文件寻找一个空闲的目录项或为其追加一个新的目录项;需修改当前目录文件的长度信息，并将当前目录文件的用户打开文件表项中的 fcbstate置为 1；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "准备好新建目录文件的 FCB的内容，文件的属性为目录文件，以覆盖写方式调用do_write()将其填写到对应的空目录项中；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{6}"
                            },
                            {
                                "type": "text",
                                "content": "在新建目录文件所分配到的磁盘块中建立两个特殊的目录项“.”和“..”目录项，方法是：首先在用户空间中准备好内容，然后以截断写或者覆盖写方式调用do_write()将其写到 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "中分配到的磁盘块中；"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                554,
                847,
                848
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\textcircled{7}"
                    },
                    {
                        "type": "text",
                        "content": "返回。"
                    }
                ]
            },
            "bbox": [
                179,
                854,
                257,
                869
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "6．删除子目录函数 rmdir()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                879,
                401,
                896
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）对应命令：my_ rmdir"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）命令调用格式：my_ rmdir dirname"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）函数设计格式：void my_rmdir(char *dirname)"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）功能：在当前目录下删除名为 dirname 的子目录。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）输入："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                90,
                608,
                190
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "dirname：欲删除目录的目录名。"
                    }
                ]
            },
            "bbox": [
                223,
                197,
                475,
                212
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（4）输出：无。"
                    }
                ]
            },
            "bbox": [
                189,
                218,
                309,
                233
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（5）函数需完成的工作："
                    }
                ]
            },
            "bbox": [
                189,
                240,
                379,
                254
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "调用do_read()读入当前目录文件内容到内存，检查当前目录下欲删除目录文件是否存在，若不存在则返回，并显示错误信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "检查欲删除目录文件是否为空（除了“.”和“..”外没有其他子目录和文件），可根据其目录项中记录的文件长度来判断，若不为空则返回，并显示错误信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "检查该目录文件是否已经打开，若已打开则调用 my_close()关闭掉；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "回收该目录文件所占据的磁盘块，修改FAT；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "从当前目录文件中清空该目录文件的目录项，且 free字段置为0：以覆盖写方式调用 do_write()来实现；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{6}"
                            },
                            {
                                "type": "text",
                                "content": "修改当前目录文件的用户打开表项中的长度信息，并将表项中的 fcbstate 置为 1；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{7}"
                            },
                            {
                                "type": "text",
                                "content": "返回。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                261,
                847,
                469
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "7．显示目录函数 my_ls()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                480,
                384,
                495
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）对应命令：my_ls"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）命令调用格式：my_ls"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）函数设计格式：void my_ls(void)"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）功能：显示当前目录的内容（子目录和文件信息）。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）输入：无"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（6）输出：无"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（7）函数需完成的工作："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                512,
                626,
                655
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "调用 do_read()读出当前目录文件内容到内存；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "将读出的目录文件的信息按照一定的格式显示到屏幕上；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "返回。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                179,
                661,
                642,
                719
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "8．创建文件函数 my_create()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                731,
                420,
                747
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）对应命令：my_create"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）命令调用格式：my_create filename"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）函数设计格式：int my_create (char *filename)"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）功能：创建名为 filename 的新文件。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）输入："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                763,
                616,
                863
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "filename：新建文件的文件名，可能包含路径。"
                    }
                ]
            },
            "bbox": [
                223,
                870,
                591,
                885
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（6）输出：若创建成功，返回该文件的文件描述符（文件打开表中的数组下标）；否"
                    }
                ]
            },
            "bbox": [
                189,
                891,
                847,
                906
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "则返回-1。"
                    }
                ]
            },
            "bbox": [
                144,
                90,
                231,
                105
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（7）函数需完成的工作："
                    }
                ]
            },
            "bbox": [
                189,
                111,
                379,
                127
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "为新文件分配一个空闲打开文件表项，如果没有空闲表项则返回-1，并显示错误信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "若新文件的父目录文件还没有打开，则调用 my_open()打开；若打开失败，则释放"
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "中为新建文件分配的空闲文件打开表项，返回-1，并显示错误信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "调用do_read()读出该父目录文件内容到内存，检查该目录下新文件是否重名，若重名则释放 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "中分配的打开文件表项，并调用my_close()关闭 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "中打开的目录文件；然后返回-1，并显示错误信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "检查FAT是否有空闲的盘块，如有则为新文件分配一个盘块，否则释放 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "中分配的打开文件表项，并调用 my_close()关闭 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "中打开的目录文件；返回-1，并显示错误信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "在父目录中为新文件寻找一个空闲的目录项或为其追加一个新的目录项;需修改该目录文件的长度信息，并将该目录文件的用户打开文件表项中的fcbstate置为 1；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{6}"
                            },
                            {
                                "type": "text",
                                "content": "准备好新文件的FCB的内容，文件的属性为数据文件，长度为0，以覆盖写方式调用 do_write()将其填写到 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "中分配到的空目录项中；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{7}"
                            },
                            {
                                "type": "text",
                                "content": "为新文件填写 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "中分配到的空闲打开文件表项，fcbstate字段值为0，读写指针值为 0；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{8}"
                            },
                            {
                                "type": "text",
                                "content": "调用 my_close()关闭 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "中打开的父目录文件；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{9}"
                            },
                            {
                                "type": "text",
                                "content": "将新文件的打开文件表项序号作为其文件描述符返回。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                131,
                848,
                489
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "9．删除文件函数 my_rm()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                179,
                501,
                384,
                517
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）对应命令：my_rm"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）命令调用格式：my_rm filename"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）函数设计格式：void my_rm(char *filename)"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）功能：删除名为 filename 的文件。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）输入："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                533,
                581,
                633
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "filename：欲删除文件的文件名，可能还包含路径。"
                    }
                ]
            },
            "bbox": [
                223,
                640,
                626,
                655
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（6）输出：无。"
                    }
                ]
            },
            "bbox": [
                189,
                662,
                309,
                676
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（7）函数需完成的工作："
                    }
                ]
            },
            "bbox": [
                189,
                683,
                379,
                697
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "若欲删除文件的父目录文件还没有打开，则调用my_open()打开；若打开失败，则返回，并显示错误信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "调用do_read()读出该父目录文件内容到内存，检查该目录下欲删除文件是否存在，若不存在则返回，并显示错误信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "检查该文件是否已经打开，若已打开则关闭掉；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "回收该文件所占据的磁盘块，修改FAT；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "从文件的父目录文件中清空该文件的目录项，且 free字段置为0：以覆盖写方式调用 do_write()来实现；；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{6}"
                            },
                            {
                                "type": "text",
                                "content": "修改该父目录文件的用户打开文件表项中的长度信息，并将该表项中的 fcbstate置为 1；"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                703,
                847,
                912
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\textcircled{7}"
                    },
                    {
                        "type": "text",
                        "content": "返回。"
                    }
                ]
            },
            "bbox": [
                184,
                90,
                253,
                105
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "10．打开文件函数 my_open()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                184,
                116,
                408,
                133
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）对应命令：my_open"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）命令调用格式：my_open filename"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）函数设计格式：int my_open(char *filename)"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）功能：打开当前目录下名为 filename的文件。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）输入："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                148,
                589,
                247
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "filename：欲打开文件的文件名"
                    }
                ]
            },
            "bbox": [
                225,
                255,
                477,
                269
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（6）输出：若打开成功，返回该文件的描述符（在用户打开文件表中表项序号）；否则返回-1。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（7）函数需完成的工作："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                275,
                847,
                334
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "检查该文件是否已经打开，若已打开则返回-1，并显示错误信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "调用do_read()读出父目录文件的内容到内存，检查该目录下欲打开文件是否存在，若不存在则返回-1，并显示错误信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "检查用户打开文件表中是否有空表项，若有则为欲打开文件分配一个空表项，若没有则返回-1，并显示错误信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "为该文件填写空白用户打开文件表表项内容，读写指针置为 0；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "将该文件所分配到的空白用户打开文件表表项序号（数组下标）作为文件描述符 fd返回。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                341,
                847,
                504
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "11．关闭文件函数 my_close()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                184,
                517,
                418,
                533
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）对应命令：my_close"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）命令调用格式：my_close fd"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）函数设计格式：void my_close(int fd)"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）功能：关闭前面由 my_open()打开的文件描述符为 fd 的文件。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）输入："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                549,
                700,
                648
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "fd：文件描述符。"
                    }
                ]
            },
            "bbox": [
                225,
                656,
                359,
                670
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（6）输出：无。"
                    }
                ]
            },
            "bbox": [
                189,
                677,
                307,
                690
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（7）函数需完成的工作："
                    }
                ]
            },
            "bbox": [
                189,
                697,
                378,
                713
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "检查fd的有效性（fd不能超出用户打开文件表所在数组的最大下标），如果无效则返回-1；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "检查用户打开文件表表项中的 fcbstate字段的值，如果为1则需要将该文件的 FCB的内容保存到虚拟磁盘上该文件的目录项中，方法是：打开该文件的父目录文件，以覆盖写方式调用do_write()将欲关闭文件的 FCB写入父目录文件的相应盘块中；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "回收该文件占据的用户打开文件表表项（进行清空操作），并将 topenfile 字段置为 0；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "返回。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                719,
                847,
                884
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "12．写文件函数 my_write()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                184,
                896,
                401,
                912
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）对应命令：my_write"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）命令调用格式：my_write fd"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）函数设计格式：int my_write(int fd)"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）功能：将用户通过键盘输入的内容写到 fd 所指定的文件中。磁盘文件的读写操作都必须以完整的数据块为单位进行，在写操作时，先将数据写在缓冲区中，缓冲区的大小与磁盘块的大小相同，然后再将缓冲区中的数据一次性写到磁盘块中；读出时先将一个磁盘块中的内容读到缓冲区中，然后再传送到用户区。本实例为了简便起见，没有设置缓冲区管理，只是在读写文件时由用户使用 malloc()申请一块空间作为缓冲区，读写操作结束后使用free()释放掉。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                90,
                848,
                275
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "写操作常有三种方式：截断写、覆盖写和追加写。截断写是放弃原来文件的内容，重新写文件；覆盖写是修改文件在当前读写指针所指的位置开始的部分内容；追加写是在原文件的最后添加新的内容。在本实例中，输入写文件命令后，系统会出现提示让用户选择其中的一种写方式，并将随后键盘输入的内容按照所选的方式写到文件中，键盘输入内容通过"
                    },
                    {
                        "type": "equation_inline",
                        "content": "\\mathrm { C T R } { + } Z"
                    },
                    {
                        "type": "text",
                        "content": "键（或其他设定的键）结束。"
                    }
                ]
            },
            "bbox": [
                144,
                282,
                850,
                382
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（5）输入："
                    }
                ]
            },
            "bbox": [
                189,
                388,
                272,
                404
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "fd： open()函数的返回值，文件的描述符；"
                    }
                ]
            },
            "bbox": [
                225,
                411,
                571,
                426
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（6）输出：实际写入的字节数。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（7）函数需完成的工作："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                432,
                431,
                469
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "检查fd的有效性（fd不能超出用户打开文件表所在数组的最大下标），如果无效则返回-1，并显示出错信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "提示并等待用户输入写方式：（1：截断写；2：覆盖写；3：追加写）"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "如果用户要求的写方式是截断写，则释放文件除第一块外的其他磁盘空间内容（查找并修改FAT表），将内存用户打开文件表项中文件长度修改为 0，将读写指针置为 0 并转"
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "；如果用户要求的写方式是追加写，则修改文件的当前读写指针位置到文件的末尾，并转"
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "；如果写方式是覆盖写，则直接转 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "提示用户：整个输入内容通过 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\mathrm { C T R } { + } Z"
                            },
                            {
                                "type": "text",
                                "content": "键（或其他设定的键）结束；用户可分多次输入写入内容，每次用回车结束；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "等待用户从键盘输入文件内容，并将用户的本次输入内容保存到一临时变量 text[]中，要求每次输入以回车结束，全部结束用 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\mathrm { C T R } { + } Z"
                            },
                            {
                                "type": "text",
                                "content": "键（或其他设定的键）；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{6}"
                            },
                            {
                                "type": "text",
                                "content": "调用do_write()函数将通过键盘键入的内容写到文件中。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{7}"
                            },
                            {
                                "type": "text",
                                "content": "如果do_write()函数的返回值为非负值，则将实际写入字节数增加do_write()函数返回值，否则显示出错信息，并转 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{9}"
                            },
                            {
                                "type": "text",
                                "content": "；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{8}"
                            },
                            {
                                "type": "text",
                                "content": "如果text[]中最后一个字符不是结束字符 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\mathrm { C T R } { + } Z"
                            },
                            {
                                "type": "text",
                                "content": "，则转 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{7}"
                            },
                            {
                                "type": "text",
                                "content": "继续进行写操作；否则转"
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{9}"
                            },
                            {
                                "type": "text",
                                "content": "；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{9}"
                            },
                            {
                                "type": "text",
                                "content": "如果当前读写指针位置大于用户打开文件表项中的文件长度，则修改打开文件表项中的文件长度信息，并将fcbstate置1；"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                475,
                848,
                854
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\textcircled{10}"
                    },
                    {
                        "type": "text",
                        "content": "返回实际写入的字节数。"
                    }
                ]
            },
            "bbox": [
                201,
                860,
                418,
                875
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "13．实际写文件函数 do_write()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                885,
                436,
                903
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）对应命令：无"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）命令调用格式：无"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）函数设计格式：int my_write(int fd，char *text，int len，char wstyle)"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）功能：被写文件函数my_write()调用，用来将键盘输入的内容写到相应的文件中去。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）输入："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                90,
                847,
                211
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "fd： open()函数的返回值，文件的描述符；"
                    }
                ]
            },
            "bbox": [
                223,
                218,
                573,
                233
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "text：指向要写入的内容的指针；"
                    }
                ]
            },
            "bbox": [
                225,
                240,
                484,
                255
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "len：本次要求写入字节数"
                    }
                ]
            },
            "bbox": [
                225,
                261,
                433,
                275
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "wstyle：写方式"
                    }
                ]
            },
            "bbox": [
                225,
                282,
                354,
                297
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（6）输出：实际写入的字节数。"
                    }
                ]
            },
            "bbox": [
                189,
                304,
                431,
                319
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（7）函数需完成的工作："
                    }
                ]
            },
            "bbox": [
                189,
                325,
                379,
                340
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "用malloc()申请1024B的内存空间作为读写磁盘的缓冲区buf，申请失败则返回-1，并显示出错信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "将读写指针转化为逻辑块块号和块内偏移 off，并利用打开文件表表项中的首块号及FAT表的相关内容将逻辑块块号转换成对应的磁盘块块号 blkno；如果找不到对应的磁盘块，则需要检索FAT为该逻辑块分配一新的磁盘块，并将对应的磁盘块块号blkno登记到FAT中，若分配失败，则返回-1，并显示出错信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "如果是覆盖写，或者如果当前读写指针所对应的块内偏移 off不等于 0，则将块号为blkno的虚拟磁盘块全部1024B的内容读到缓冲区buf中；否则便用ASCII码0清空buf；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "将text中未写入的内容暂存到缓冲区 buff 的第 off字节开始的位置，直到缓冲区满，或者接收到结束字符 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\mathrm { C T R } { + } Z"
                            },
                            {
                                "type": "text",
                                "content": "为止；将本次写入字节数记录到tmplen中；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "将 buf 中 1024B 的内容写入到块号为 blkno 的虚拟磁盘块中；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{6}"
                            },
                            {
                                "type": "text",
                                "content": "将当前读写指针修改为原来的值加上 tmplen；并将本次实际写入的字节数增加tmplen；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{7}"
                            },
                            {
                                "type": "text",
                                "content": "如果 tmplen 小于 len，则转 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "继续写入；否则转 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{8}"
                            },
                            {
                                "type": "text",
                                "content": "；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{8}"
                            },
                            {
                                "type": "text",
                                "content": "返回本次实际写入的字节数。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                347,
                847,
                661
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "14．读文件函数 my_read()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                671,
                393,
                689
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）对应命令：my_read"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）命令调用格式：my_read fd len"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）函数设计格式：int myread (int fd, int len)"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）功能：读出指定文件中从读写指针开始的长度为 len的内容到用户空间中。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）输入："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                705,
                801,
                804
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "fd： open()函数的返回值，文件的描述符；"
                    }
                ]
            },
            "bbox": [
                223,
                810,
                571,
                826
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "len: 要从文件中读出的字节数。"
                    }
                ]
            },
            "bbox": [
                225,
                833,
                494,
                847
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（6）输出：实际读出的字节数。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（7）函数需完成的工作："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                854,
                431,
                890
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\textcircled{1}"
                    },
                    {
                        "type": "text",
                        "content": "定义一个字符型数组text[len]，用来接收用户从文件中读出的文件内容；"
                    }
                ]
            },
            "bbox": [
                179,
                897,
                779,
                913
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "检查fd的有效性（fd不能超出用户打开文件表所在数组的最大下标），如果无效则返回-1，并显示出错信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "调用 do_read()将指定文件中的 len 字节内容读出到 text[]中；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "如果do_read()的返回值为负，则显示出错信息；否则将text[]中的内容显示到屏幕上；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "返回。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                90,
                845,
                212
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "15．实际读文件函数 do_read()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                223,
                428,
                240
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）对应命令：无"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）命令调用格式：无"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）函数设计格式：int do_read (int fd, int len,char *text)"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）功能：被my_read()调用，读出指定文件中从读写指针开始的长度为 len 的内容到用户空间的 text 中。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）输入："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                255,
                843,
                376
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "fd： open()函数的返回值，文件的描述符；"
                    }
                ]
            },
            "bbox": [
                223,
                384,
                571,
                399
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "len: 要求从文件中读出的字节数。"
                    }
                ]
            },
            "bbox": [
                225,
                405,
                510,
                420
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "text：指向存放读出数据的用户区地址"
                    }
                ]
            },
            "bbox": [
                225,
                426,
                529,
                441
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（6）输出：实际读出的字节数。"
                    }
                ]
            },
            "bbox": [
                189,
                448,
                431,
                463
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "text",
                        "content": "（7）函数需完成的工作："
                    }
                ]
            },
            "bbox": [
                189,
                469,
                378,
                483
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "使用malloc()申请 1024B空间作为缓冲区 buf，申请失败则返回-1，并显示出错信息；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "将读写指针转化为逻辑块块号及块内偏移量 off，利用打开文件表表项中的首块号查找FAT表，找到该逻辑块所在的磁盘块块号；将该磁盘块块号转化为虚拟磁盘上的内存位置；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "将该内存位置开始的 1024B（一个磁盘块）内容读入 buf 中；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "比较buf中从偏移量off开始的剩余字节数是否大于等于应读写的字节数len，如果是，则将从off开始的buf中的len长度的内容读入到 text[]中；否则，将从 off开始的buf中的剩余内容读入到 text[]中；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{5}"
                            },
                            {
                                "type": "text",
                                "content": "将读写指针增加 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "中已读字节数，将应读写的字节数 len减去 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "中已读字节数，若len大于0，则转 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "；否则转 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{6}"
                            },
                            {
                                "type": "text",
                                "content": "；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{6}"
                            },
                            {
                                "type": "text",
                                "content": "使用 free()释放 "
                            },
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "中申请的 buf。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{7}"
                            },
                            {
                                "type": "text",
                                "content": "返回实际读出的字节数。"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                144,
                489,
                847,
                762
            ]
        },
        {
            "type": "title",
            "content": {
                "title_content": [
                    {
                        "type": "text",
                        "content": "16. 退出文件系统函数 my_exitsys()"
                    }
                ],
                "level": 1
            },
            "bbox": [
                181,
                772,
                472,
                790
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）对应命令：my_exitsys"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）命令调用格式：my_ exitsys"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                806,
                450,
                843
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（1）函数设计格式：void my_exitsys()"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（2）功能：退出文件系统。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（3）输入：无"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                848,
                500,
                906
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                63
            ]
        }
    ],
    [
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（4）输出：无。"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "text",
                                "content": "（5）函数需完成的工作："
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                189,
                90,
                379,
                126
            ]
        },
        {
            "type": "list",
            "content": {
                "list_type": "text_list",
                "list_items": [
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{1}"
                            },
                            {
                                "type": "text",
                                "content": "使用 C 库函数 fopen()打开磁盘上的 myfsys 文件；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{2}"
                            },
                            {
                                "type": "text",
                                "content": "将虚拟磁盘空间中的所有内容保存到磁盘上的 myfsys 文件中；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{3}"
                            },
                            {
                                "type": "text",
                                "content": "使用 c 语言的库函数 fclose()关闭 myfsys 文件；"
                            }
                        ]
                    },
                    {
                        "item_type": "text",
                        "item_content": [
                            {
                                "type": "equation_inline",
                                "content": "\\textcircled{4}"
                            },
                            {
                                "type": "text",
                                "content": "撤销用户打开文件表，释放其内存空间"
                            }
                        ]
                    }
                ]
            },
            "bbox": [
                179,
                131,
                685,
                212
            ]
        },
        {
            "type": "paragraph",
            "content": {
                "paragraph_content": [
                    {
                        "type": "equation_inline",
                        "content": "\\textcircled{4}"
                    },
                    {
                        "type": "text",
                        "content": "释放虚拟磁盘空间。"
                    }
                ]
            },
            "bbox": [
                215,
                214,
                410,
                229
            ]
        },
        {
            "type": "page_header",
            "content": {
                "page_header_content": [
                    {
                        "type": "text",
                        "content": "版权归杭州电子科技大学计算机学院"
                    }
                ]
            },
            "bbox": [
                374,
                49,
                621,
                61
            ]
        }
    ]
]