C 返回结构的API

C 返回结构的API,c,api,struct,C,Api,Struct,以下情况下的最佳解决方案是什么: 我们的API向用户返回一个结构 我们希望用户能够阅读其内容 我们不希望用户更改它,因为它可能被传递给其他API函数,并且其内容应该是正确的 我认为每次使用调用此函数时,您都可以复制此结构并返回副本以供使用 这样,每次调用函数时,都会创建一个新副本 同样,您可以让用户malloc一个memory并给API地址,API只需使用memset来填充地址,这样用户就可以在使用完数据后释放内存 如果不想将结构存储在任何地方,也可以使用不透明指针 附言:我说我命令中的第三个

以下情况下的最佳解决方案是什么:

  • 我们的API向用户返回一个结构
  • 我们希望用户能够阅读其内容
  • 我们不希望用户更改它,因为它可能被传递给其他API函数,并且其内容应该是正确的

我认为每次使用调用此函数时,您都可以复制此结构并返回副本以供使用

这样,每次调用函数时,都会创建一个新副本

同样,您可以让用户
malloc
一个memory并给API地址,API只需使用
memset
来填充地址,这样用户就可以在使用完数据后释放内存

如果不想将结构存储在任何地方,也可以使用不透明指针


附言:我说我命令中的第三个建议,然后我得到了否决票,而我看到其他人把这个添加到他的答案中并得到了赞成票,而我们都没有这一行,这怎么会发生呢

不是返回结构,而是返回一些可以让您恢复结构的内容(指向结构的指针应该可以工作,但您可以使用其他内容),也不是让用户访问其字段,而是为用户提供一组用于访问这些字段的函数(或宏)


我认为这被称为不透明指针。

如果您不希望用户弄乱结构内部,您可以返回一个只能使用您定义的访问器函数读取的指针。

您无法阻止用户访问结构的内容。如果这是一项要求,则必须返回一个不透明值,并添加一个API以获取其中一个不透明值并从中返回各个值。

若要在此扩展答案,建议使用不透明的
结构

在C语言中,很少有方法阻止人们访问您的数据。如果您将
structs
作为公共API的参数和返回值,则可以通过一些方法隐藏数据,或者按照合同强制用户不访问所述数据

不透明的
struct
s最常见的用法可能是
文件*
。使用标准库读取/写入/查询文件时,只需将
struct file*
传递给libc I/O函数之一,如
fwrite
。查看结构会导致未定义的行为,因为不能保证跨平台的实现是相同的

如果希望用户能够修改某些数据,但不能修改其他数据,则可以执行以下操作:

typedef struct 
{
    void * _my_private_data; //KEEP OUT
    char * name;
    int count;
    //etc
}my_api_type;
然后,您可以定义向用户公开的所有函数调用的第一个参数,以获取其中一个
结构

my_api_type set_internal_标志(my_api_type*obj,int标志)


确保您的私人数据保持隐藏,您的实现可以保证,无论您如何定义
void*
后面的结构,您的API函数都可以跨规范更改保持兼容,并且用户不必在更新某些内容时修改其代码。

您的函数可以返回指向常量结构的指针。然后:

  • 不允许调用方通过指向const结构的指针修改结构。C实现应该执行此规则
  • 如果调用方将指向常量结构的指针传递给API中的另一个函数,则C规则允许该函数将指向常量结构的指针转换为指向非常量结构的指针。如果结构未定义为常量(例如,它被创建为非常量,但指向它的指针被转换为指向常量结构的指针),则允许函数通过新转换的指向非常量结构的指针修改结构
  • C规则还允许调用方进行相同的转换和修改。显然,打电话的人不应该这样做,而你是依靠他们的善意才不这样做的。因此,此技术可防止通过返回的指针进行无意修改,但不能防止通过转换的指针进行恶意修改
更进一步,您只能向调用者提供不完整的结构声明,该声明只显示其名称(如
struct foo;
),而不定义其内容(如
struct foo{int x;…};
)。当调用者只有一个不完整的结构声明时,他们可以接收指向该结构的指针,并可以将其存储并作为参数传递,但他们不能使用它访问该结构(除非通过异常手段,例如将其转换为指向另一种类型的指针或提供自己的结构定义)


如果调用者只有不完整的结构声明,但必须能够使用结构的内容,则必须提供附加函数,该函数接受指向结构的指针作为参数,并从结构内部返回信息。

您不能强制执行“我们不希望用户更改它”无需以某种方式为数据创建不透明的API。那真的很乏味。我会说让用户做他们想做的;您不能在每一个级别上防止误用。是否有必要将结构返回给用户,或者返回指向结构的指针是可以接受的?如果是这样,您可以返回指向
const
结构的指针。C仅部分强制执行该规定;实现不应允许通过指向常量结构的指针进行修改,但必须允许将指针转换为指向非常量的指针。@EricPostIschil:这实际上是我目前为止在该线程中最喜欢的想法。是的,但它是传递给其他API函数的副本。@user2656304否,每次调用函数时,都会创建一个新的副本。对不起,实际上没有“副本”,因为我们不存储结构