zoukankan      html  css  js  c++  java
  • 可调式性编码(增量开发) yongmou

       可调式性编码意味着把系统分成几个部分,先让程序总体结构运行。只有基本的程序能够运行之后你才能为那些复杂的细节完善、性能调优和算法优化进行编码。
       有时候,花点时间把编程问题分解成几个部分往往是解决它的最快办法。

       下面给出几个例子: 

     写散列表 

       自己以前也写过,记得调试时候好痛苦,那么大的散列,找起数据来一点都不方便。

       《C专家编程》中作者叙述他的同事这样写散列表:

       他首先让最简单的情况能够运行,就是散列函数总是返回一个0。散列函数如下:

    /* hash_file: Placeholder for more sophisticated future
    routine
    */
    int hash_filename (char *s){
        return 0;
    }
    调用这个散列函数的代码如下:
    /*
    * find_file: Locate a previously created file descriptor or make a new one if necessary.
    */
    file find_filename (
    char *s)
    {
      int hash_value = hash_filename(s);
      file f;
      for (f = file_hash_table[hash_value]; f != NIL;f=f->flink) {
        if (strcmp(f->fname, s) == SAME) {
          return f;
        }
      }
      /* file not found, so make a new one: */
      f
    = allocate_file(s);
      f
    ->flink = file_hash_table[hash_value];
      file_hash_table[hash_value]
    = f;
      return f;
    }
    它的效果就像是一个散列表还未使用。所有的元素都存储在第0个位置后面的链表中。这使得程序很容易调式。当他的主程序能够完美运行后,才开始着手优化措施。

     FSM实现cdecl

      cdecl是分析C语言的声明并把它们翻译成通俗语言。

       有限自动机(FSM)可以用作程序的控制结构。

      它的基本思路是用一张表保存所有可能的状态,并列出进入每个状态时可能执行的所有动作,其中最后一个动作就是计算(通常在当前状态和下一次输入字符的基础上,另外再经过一次表查询)下一个应该进入的状态。你从一个“初始状态”开始。在这一过程中,翻译表可能告诉你进入了一个错误的状态,表示一个预期之外的或错误的输入。你不停地在各种状态间转换,直到到达结束状态。

       在C语言中,有好几种方法可以用来表达FSM,但他们绝大多数都是基于函数指针数组。一个函数指针数组可以像下面这样声明:
     void (*state)[MAX_STATES]();

      不过这个例子,只需要一个函数函数指针就够了。在主循环里,程序将调用指针所指向的函数,并循环往复,直到结束函数被调用(到达FSM的终结状态)或遇到一个错误状态。

      1. 状态机图,详见《C专家编程》第3章

      2. 首先编写代码控制状态的转换。让每个动作程序简单打印一条信息,显示它已被调用。对他进行深入调试。

      3. 增加代码处理并分析输入的声明。

      完整代码:

    View Code
    /*
    * FSM 实现 cdecl
    */

    #include
    <stdio.h>
    #include
    <string.h>
    #include
    <ctype.h>

    #define MAXTOKENS 100
    #define MAXTOKENLEN 64

    enum type_tag {
    IDENTIFIER, QUALIFIER, TYPE
    };
    // 标识符,限定符,类型

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

    int top = -1;
    struct token stack[MAXTOKENS]; // 保存第一个标识符之前的所有标记
    struct token this; // 保存刚刚读入的那个标记

    #define pop stack[top--]
    #define push(s) stack[++top] = s

    enum type_tag classify_string(void) { /* 字符串分类,推断标识符类型 */
    char *s = this.string;
    if (strcmp(s, "const") == 0) {
    strcpy(s,
    "read-only");
    return QUALIFIER;
    }
    if (strcmp(s, "volatile") == 0)
    return QUALIFIER;
    if (strcmp(s, "void") == 0)
    return TYPE;
    if (strcmp(s, "char") == 0)
    return TYPE;
    if (strcmp(s, "signed") == 0)
    return TYPE;
    if (strcmp(s, "unsigned") == 0)
    return TYPE;
    if (strcmp(s, "short") == 0)
    return TYPE;
    if (strcmp(s, "int") == 0)
    return TYPE;
    if (strcmp(s, "long") == 0)
    return TYPE;
    if (strcmp(s, "float") == 0)
    return TYPE;
    if (strcmp(s, "double") == 0)
    return TYPE;
    if (strcmp(s, "struct") == 0)
    return TYPE;
    if (strcmp(s, "union") == 0)
    return TYPE;
    if (strcmp(s, "enum") == 0)
    return TYPE;
    return IDENTIFIER;
    }

    void gettoken(void) { /* 读取下一个标记到”this“ */
    char *p = this.string;

    // 略过空白字符
    while ((*p = getchar()) == ' ')
    ;

    if (isalnum(*p)) {
    // 读入的标识符以A-Z,0-9开头
    while (isalnum(*++p = getchar()))
    ;
    ungetc(
    *p, stdin);
    *p = '\0';
    this.type = classify_string();
    return;
    }
    this.string[1] = '\0';
    this.type = *p;
    return;
    }

    /* 状态函数 */
    void initialize(), get_array(), get_params(), get_lparen(), get_ptr_part(),
    get_type();

    void (*nextstate)(void) = initialize;

    int main() {
    /* 在不同的状态间切换,直到指针值为NULL */
    while (nextstate != NULL)
    (
    *nextstate)();
    return 0;
    }

    void initialize() {
    gettoken();
    while (this.type != IDENTIFIER) {
    push(
    this);
    gettoken();
    }
    printf(
    "%s is ", this.string);
    gettoken();
    nextstate
    = get_array;
    }

    void get_array() {
    nextstate
    = get_params;
    while (this.type == '[') {
    printf(
    "array ");
    gettoken();
    /* a number or ']' */
    if (isdigit(this.string[0])) {
    printf(
    "0..%d ", atoi(this.string) - 1);
    gettoken();
    /* read the ']' */
    }
    gettoken();
    /* read next past the ']' */
    printf(
    "of ");
    nextstate
    = get_lparen;
    }
    }

    void get_params() {
    nextstate
    = get_lparen;
    if (this.type == '(') {
    while (this.type != ')') {
    gettoken();
    }
    gettoken();
    printf(
    "function returning ");
    }
    }

    /* 左小括号 */
    void get_lparen() {
    nextstate
    = get_ptr_part;
    if (top >= 0) {
    if (stack[top].type == '(') {
    pop;
    gettoken();
    /* read past ')' */
    nextstate
    = get_array;
    }
    }
    }

    void get_ptr_part() {
    nextstate
    = get_type;
    if (stack[top].type == '*') {
    printf(
    "pointer to ");
    pop;
    nextstate
    = get_lparen;
    }
    else if (stack[top].type == QUALIFIER) {
    printf(
    "%s ", pop.string);
    nextstate
    = get_lparen;
    }
    }

    void get_type() {
    nextstate
    = NULL;
    /* process tokens that we stacked while reading to
    identifier
    */
    while (top >= 0) {
    printf(
    "%s ", pop.string);
    }
    printf(
    "\n");
    }

     

  • 相关阅读:
    配置nova服务使用ceph作为后端存储
    配置glance使用ceph作为后端存储
    配置nova-compute在不同的hypervisors上使用不同的存储后端
    配置cinder-backup服务使用ceph作为后端存储
    配置cinder-volume服务使用ceph作为后端存储
    安装cinder
    利用ceph-deploy安装ceph
    安装neutron
    安装nova
    安装glance
  • 原文地址:https://www.cnblogs.com/liyongmou/p/1964410.html
Copyright © 2011-2022 走看看