gpt4 book ai didi

用于盘上层次结构的 C API 设计 - 最佳实践

转载 作者:行者123 更新时间:2023-12-04 07:08:16 26 4
gpt4 key购买 nike

我正在编写我的第一个主要 C API,我想把事情做好。该库为内部结构分配和释放内存 - 使用 typedef 对客户端隐藏。我提供访问的数据的粗略结构是这样的:

光盘->节目->轨道

与光盘相关的是要读取的文件描述符、文件大小、程序数量和一些光盘范围的属性。

与程序相关的是诸如光盘中的(程序)索引、文件中的物理偏移、轨道数和名称之类的东西。

与轨道相关的是程序中的(轨道)索引、名称和文件中的一堆偏移量。

每个结构都有一个指向父结构的指针。

我有几个问题,但我会尽量保持简短:

  • 轨道/程序是否应该知道它在父结构中的哪个索引?
  • 这种结构层次结构看起来相当复杂,但另一种方法是将程序和/或轨道索引传递给各种函数。哪个更可取?
  • 还有更一般的评论吗?

  • 这是一个类似文件系统的结构(但它是只读的),我希望它将来能够与多线程兼容,并且它需要是可移植的。我在这里专门谈论 C - 没有 C++。

    最佳答案

    大量编辑介绍 我最初批评问题描述令人困惑。我的问题源于问题中使用"file"概念的方式。这个问题意味着光盘、程序和轨道都存储在一个"file"中。我以为提问者正在构建他自己的文件系统,这会使“一个文件中的所有内容”结构变得奇怪,但我现在决定他可能不会这样做,在这种情况下,它就不那么奇怪了。所以我将继续提供一个真正的答案,基于他使用现有(可能是标准)文件系统的假设,并且他的整个数据结构存储在该文件系统中的一个文件中。如果我假设错误,毫无疑问我会得到纠正。

    对于这种情况,我将首先提供一条一般性建议;首先从 API 用户的角度看问题。然后设计您的 API,以便他将编写的代码轻松流动,而无需处理您域中正确的细节。

    处理 API 设计的一种方法是先编写一些用户代码并定义 API,以便代码易于编写。作为奖励,在您实际实现 API 之后,您将拥有一些测试代码来试用它。

    继续提供更具体的建议;

    这是系统中三种数据类型的目录。如果您愿意,我们可以将它们视为抽象数据类型或“对象”,并定义一个 typdef 结构(如 DISC、PROGRAM、TRACK)来表示每个类型。

    disc = a collection of programs stored in a file
    +-----------+
    |file |
    +-----------+
    |program |
    +-----------+
    |program |
    +-----------+
    |... |
    +-----------+
    |program |
    +-----------+

    program = a collection of tracks
    +-----------+
    |ptr->disc |
    +-----------+
    |name |
    +-----------+
    |file offset|
    +-----------+
    |track |
    +-----------+
    |track |
    +-----------+
    |... |
    +-----------+
    |track |
    +-----------+

    track = a collection of audio samples
    +------------------+
    |ptr->program |
    +------------------+
    |name |
    +------------------+
    |file offset+length|
    +------------------+
    |file offset+length|
    +------------------+
    |... |
    +------------------+
    |file offset+length|
    +------------------+

    我建议您不要让您的用户从结构中挑选数据。你不能真正隐藏 C 中结构的内部结构(不用通过转换等跳过箍),但是你可以提供一系列函数,让你的用户在不访问抽象类型的内容的情况下做他们需要做的事情他们自己。例如,我们的函数族可能是这样的;
    // DISC functions
    DISC *dopen( const char *disc_name );
    void dstats( int *ptr_nbr_programs, FILE **ptr_file );
    void dclose( DISC *disc );

    // PROGRAM functions
    PROGRAM *popen_name( DISC *disc, const char *program_name );
    PROGRAM *popen_idx ( DISC *disc, int program_idx );
    void pstats( int *ptr_nbr_tracks );
    void pclose( PROGRAM *program );

    // TRACK functions
    TRACK *topen_name( PROGRAM *program, const char *track_name );
    TRACK *topen_idx ( PROGRAM *program, int track_idx );
    int tread( unsigned char *buf, int nbytes_to_read );
    void tseek( unsigned long offset );
    void tclose( TRACK *track );

    这一切都应该是不言自明的——它以现有的标准 C FILE 范例为模型。

    首先,您的用户使用 dopen() 获得一个指向 DISC 的 ptr。假设这有效(如果无效,它将返回 NULL),他可以使用 dstats() 获取任何全局 DISC 信息。更重要的是,他可以使用 popen() 系列函数之一获得 DISC 中 PROGAM 的 ptr。

    通过指向 PROGRAM 的 ptr,他可以进一步向下钻取并使用 topopen() 系列函数之一获得单个 TRACK。

    非常重要的一点是,您不要让用户自己遍历音频片段以从 TRACK 获取数据。用户提供一个缓冲区来读取样本,您可以根据需要遍历片段以填充该缓冲区。 tseek() 函数提供给他随机访问。

    我没有试图弄清楚每个参数的细节以及如何处理错误等,我只是提出一个需要改进的概念。

    请注意,“三明治”范式贯穿始终。介绍性的“打开”和结束的“关闭”三明治操作对每种类型进行。

    关于用于盘上层次结构的 C API 设计 - 最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/770543/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com