其他分享
首页 > 其他分享> > menu实验代码的分析

menu实验代码的分析

作者:互联网

致谢

首先感谢孟宁老师的教学指导。这篇文章主要基于孟宁老师上课的内容完成。

仔细阅读分析源代码,结合代码分析其中的软件工程方法、规范或软件工程思想。具体要求如下:
对模块化设计、可重用接口、线程安全等议题结合代码进行理解和分析;

vscode c++环境配置

vscode安装c/c++扩展以MAC为例

  1. 点击1号位置
  2. 在2号位置输入c搜索
  3. 安装如图扩展

下载Mingw-w64/GCC编译器

为了在不同环境下保持一致,我们选择Mingw-w64/GCC
brew install gcc gdb # for macOS
可能需要运行xcode-select —install 和brew update
sudo apt install build-essential gdb # for Ubuntu Linux
可能需要运行sudo apt update
https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/installer/mingw-w64-install.exe for windows

配置vscode配置文件

  1. 进入一个目录,创建一个cpp文件,我创建的文件如下
  2. 使用快捷键command+shift+p,再输入edit回车生成如下文件
    • 原始值为
{
    "configurations": [
        {
            "name": "Mac",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "defines": [],
            "macFrameworkPath": [
                "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks"
            ],
            "compilerPath": "/usr/bin/clang",
            "cStandard": "c11",
            "cppStandard": "c++17",
            "intelliSenseMode": "clang-x64"
        }
    ],
    "version": 4
}
{
  "configurations": [
    {
      "name": "Mac",
      "includePath": [
        "${workspaceFolder}/**",
        "/Library/Developer/CommandLineTools/usr/include/c++/v1",
        "/usr/local/include",
        // "/Library/Developer/CommandLineTools/usr/lib/clang/9.0.0/include",
        "/Library/Developer/CommandLineTools/usr/include"
        // "/usr/include"
      ],
      "defines": [],
      "macFrameworkPath": ["/System/Library/Frameworks", "/Library/Frameworks"],
      "compilerPath": "/usr/bin/clang",
      "cStandard": "c11",
      "cppStandard": "c++17",
      "intelliSenseMode": "clang-x64"
    }
  ],
  "version": 4
}
  1. command+shift+p打开命令行工具窗口,输入或者选择Tasks: Configure Task
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "command": "msbuild",
            "args": [
                // Ask msbuild to generate full paths for file names.
                "/property:GenerateFullPaths=true",
                "/t:build",
                // Do not generate summary otherwise it leads to duplicate errors in Problems panel
                "/consoleloggerparameters:NoSummary"
            ],
            "group": "build",
            "presentation": {
                // Reveal the output only if unrecognized errors occur.
                "reveal": "silent"
            },
            // Use the standard MS compiler pattern to detect errors, warnings and infos
            "problemMatcher": "$msCompile"
        }
    ]
}
{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "label": "c++",
      "command": "clang++",
      "type": "shell",
      "args": ["./c++/hello.cpp", "-std=c++11", "-g"],
      "presentation": {
        "echo": true,
        "reveal": "always",
        "focus": false,
        "panel": "shared"
      }
    }
  ]
}

  1. 修改launch.json
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(lldb) 启动",
            "type": "cppdbg",
            "request": "launch",
            "program": "输入程序名称,例如 ${workspaceFolder}/a.out",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "lldb"
        }
    ]
}
{
  // 使用 IntelliSense 了解相关属性。
  // 悬停以查看现有属性的描述。
  // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "name": "c/c++ Launch",
      "type": "cppdbg",
      "request": "launch",
      "program": "${workspaceFolder}/a.out",
      "args": [],
      "stopAtEntry": false,
      "cwd": "${workspaceFolder}",
      "environment": [],
      "externalConsole": true,
      "MIMode": "lldb",
      "preLaunchTask": "c++"
    }
  ]
}

更具体配置可参考:https://code.visualstudio.com/docs/cpp/config-clang-mac

源码分析

软件工程方法和规范

在此模块中的具体体现就是:在.h文件中进行函数声明,在.c文件中进行具体的函数实现。如下图:
menu.h

menu.c

注释和版权信息:注释也要使用英文,不要使用中文或特殊字符,要保持源代码是ASCII字符格式文件;
不要解释程序是如何工作的,要解释程序做什么,为什么这么做,以及特别需要注意的地方;
每个源文件头部应该有版权、作者、版本、描述等相关信息。
- 在代码中的具体体现:

不同语言都有其命名规范,C语言变量命名是驼峰式的,在老师的代码中体现的淋漓尽致。

struct LinkTable
{
    tLinkTableNode *pHead;
    tLinkTableNode *pTail;
    int			SumOfNode;
    pthread_mutex_t mutex;

};
      ```
这里还增加了一个锁,增加了操作的安全性。

      2.1 内聚度与耦合度
      内聚度是指一个软件模块内部各种元素之间互相依赖的紧密程度。理想的内聚是功能内聚,也就是一个软件模块只做一件事,只完成一个主要功能点或者一个软件特性(Feather)。
      在这个模块设计中如何体现:
      - 体现1:
      ![](https://www.icode9.com/i/l/?n=20&i=blog/2164312/202010/2164312-20201028191500636-1183978996.png)
      `linktable`这两个文件中主要是对操作节点链的处理。每增加或者删除一个操作,只要调用这两个文件里面的函数即可,而不用再自己写了。
      增加了复用性,降低了耦合性。
      - 体现2:

      ```
/* show all cmd in listlist */
int ShowAllCmd(tLinkTable * head)
{
    tDataNode * pNode = (tDataNode*)GetLinkTableHead(head);
    while(pNode != NULL)
    {
        printf("    * %s - %s\n", pNode->cmd, pNode->desc);
        pNode = (tDataNode*)GetNextLinkTableNode(head,(tLinkTableNode *)pNode);
    }
    return 0;
}

int Help(int argc, char *argv[])
{
    ShowAllCmd(head);
    return 0; 
}

int SetPrompt(char * p)
{
    if (p == NULL)
    {
        return 0;
    }
    strcpy(prompt,p);
    return 0;
}
/* add cmd to menu */
int MenuConfig(char * cmd, char * desc, int (*handler)())
{
    tDataNode* pNode = NULL;
    if ( head == NULL)
    {
        head = CreateLinkTable();
        pNode = (tDataNode*)malloc(sizeof(tDataNode));
        pNode->cmd = "help";
        pNode->desc = "Menu List";
        pNode->handler = Help;
        AddLinkTableNode(head,(tLinkTableNode *)pNode);
    }
    pNode = (tDataNode*)malloc(sizeof(tDataNode));
    pNode->cmd = cmd;
    pNode->desc = desc;
    pNode->handler = handler; 
    AddLinkTableNode(head,(tLinkTableNode *)pNode);
    return 0; 
}


/* Menu Engine Execute */
int ExecuteMenu()
{
   /* cmd line begins */
    while(1)
    {
		int argc = 0;
		char *argv[CMD_MAX_ARGV_NUM];
        char cmd[CMD_MAX_LEN];
		char *pcmd = NULL;
        printf("%s",prompt);
        /* scanf("%s", cmd); */
		pcmd = fgets(cmd, CMD_MAX_LEN, stdin);
		if(pcmd == NULL)
		{
			continue;
		}
        /* convert cmd to argc/argv */
		pcmd = strtok(pcmd," ");
		while(pcmd != NULL && argc < CMD_MAX_ARGV_NUM)
		{
			argv[argc] = pcmd;
			argc++;
			pcmd = strtok(NULL," ");
		}
        if(argc == 1)
        {
            int len = strlen(argv[0]);
            *(argv[0] + len - 1) = '\0';
        }
        tDataNode *p = (tDataNode*)SearchLinkTableNode(head,SearchConditon,(void*)argv[0]);
        if( p == NULL)
        {
            continue;
        }
        printf("%s - %s\n", p->cmd, p->desc);
        if(p->handler != NULL) 
        { 
            p->handler(argc, argv);
        }
    }
} 
      ```

这里主要是把添加的菜单项放入menu中。功能集中,内聚度低,里面的其他功能直接复用上面已经定义的节点操作,耦合度低。
      2.2 接口模块
      软件模块接口在面向过程的语言中一般是定义一些数据结构和函数接口API,在面向对象的编程语言中一般在类或接口类中定义一些公有的(public)属性和方法。两类编程语言中接口形式上有很大不同,但是不管是函数接口API还是公有的方法本质上都是函数定义。我们将重点介绍两种函数接口方式,即Call-in方式的函数接口和Callback方式的函数接口。这里我们先来理解函数接口规格。

      具体体现:
      `tLinkTableNode * GetLinkTableHead(tLinkTable *pLinkTable);`
      该接口的目标是从链表中取出链表的头节点,函数名GetLinkTableHead清晰明确地表明了接口的目标;
      该接口的目标是从链表中取出链表的头节点,函数名GetLinkTableHead清晰明确地表明了接口的目标;
      该接口的前置条件是链表必须存在使用该接口才有意义,也就是链表pLinkTable != NULL;
      使用该接口的双方遵守的协议规范是通过数据结构tLinkTableNode和tLinkTable定义的;
      使用该接口之后的效果是找到了链表的头节点,这里是通过tLinkTableNode类型的指针作为返回值来作为后置条件,C语言中也可以使用指针类型的参数作为后置条件;
      该接口没有特别要求接口的质量属性,如果搜索一个节点可能需要在可以接受的延时时间范围内完成搜索;

标签:函数,int,menu,代码,cmd,接口,pNode,实验,tDataNode
来源: https://www.cnblogs.com/shizi-4/p/13890512.html