代码之家  ›  专栏  ›  技术社区  ›  Vinko Vrsalovic

C语言中的可重入库设计

  •  6
  • Vinko Vrsalovic  · 技术社区  · 15 年前

    假设我正在建一个图书馆,以便在C.

    quuxes需要两个状态变量才能成功地进行sporked:

    static int quux_state;
    static char* quux_address;
    
    /* function to spork quuxes found in a file, 
       reads a line from the file each time it's called. */
    void spork_quux(FILE*);
    

    如果我将这些数据存储为全局变量,那么只有一个客户机能够在同一时间发现quuxes,否则状态变量会被第二个调用者破坏,从而导致灾难。

    问题是,用C语言设计可重入库的最佳方法是什么?

    我受理了以下案件,没有得出令人满意的结论。

    在以下情况下,问题是如何将客户机关联到每个状态?

    /* library handles all state data allocation */
    static int* quux_state; 
    static char** quux_address;
    

    在下面的情况下,客户能够处理状态,非常不受欢迎

    /* let each client store state */
    typedef struct { int state; char* address; } QuuxState; 
    QuuxState spork_quux(FILE*);
    

    那么,如何正确地做到这一点呢?

    3 回复  |  直到 15 年前
        1
  •  21
  •   JosephH    15 年前

    使用结构,但不要向客户端公开定义。

    即在.h头文件中输入:

    typedef struct QuuxState QuuxState;
    
    QuuxState *spork_quux(FILE*);
    

    在.c实现文件中:

    struct QuuxState
    {
        int state;
        char* address;
    };
    
    QuuxState *spork_quuxFILE *f)
    {
        QuuxState *quuxState = calloc(1, sizeof(*quuxState));
        if (!quuxState)
            return NULL;
    
        quuxState->state = ....;
    
        ........
    
        return quuxState;
    }
    

    这种方法的优点是:

    1. 您可以在不重新编译所有客户端代码的情况下更改结构的内容
    2. 客户端代码无法访问成员,即quuxstate->状态将给出编译器错误
    3. QuuxState结构对调试器仍然是完全可见的,因此您可以看到非常普通的值和设置观察点等。
    4. 无需铸造
    5. 您返回的类型是一个特定的类型,因此您将得到一些编译器检查传递的内容是否正确(与void*指针相比)。

    唯一的缺点是您必须分配一个内存块——但是假设您的库在做一些不重要的事情(如果它在做文件I/O,那肯定是不重要的),单个malloc的开销可以忽略不计。

    您可能希望将上述函数重命名为类似于“quuxsork_create”的函数,并添加更多的函数来处理逐行执行的工作以及完成后销毁状态。

    void QuuxSpork_readLine(QuuxState *state)
    {
        ....
    }
    
    void QuuxSpork_destroy(QuuxState *state)
    {
        free(state);
    }
    

    像这样工作的库的随机例子是POSIX线程库pthreads。

        2
  •  3
  •   Seva Alekseyev    15 年前

    使用结构,但不要告诉客户它是结构。传递一个不透明的指针-void*,或者更好的方法是指向空的伪结构的指针-并在需要时将其强制转换回来。

        3
  •  1
  •   Rannick    15 年前

    大多数库函数处理这种情况的方法是,以用户需要的任何数据类型将状态信息返回给用户。在您的例子中,是一个结构。(以strtok和strtok-r为例)。我相信这是一个先例,你应该把它传给用户。空虚*起作用。你甚至可以用typedef来修饰它,使它看起来漂亮。

    此外,strtok_r通过编辑命令行参数来实现这一点,而不是返回指向状态的指针。我希望我使用的任何可重入函数都遵循类似的格式。当然,我的大脑被一些非常疯狂的C代码扭曲了。

    void spork_quux(FILE*, QuuxState **);