首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C中函数值的返回方法

C中函数值的返回方法
EN

Stack Overflow用户
提问于 2013-01-08 19:37:19
回答 3查看 179关注 0票数 1

在用C编写函数时,有哪些考虑因素决定函数返回结果的方式?我的问题来自于阅读以下代码,它在双链接列表中创建一个节点,它来自图书:

代码语言:javascript
运行
复制
typedef struct DLLIST
{
    uint16 tag;                 /* This node's object type tag */
    struct DLLIST *next;
    struct DLLIST *previous;
    void *object;
    uint32 size;                /* This node's object size */
} DLLIST;

DLLIST *dlCreate(uint16 tag, void *object, uint32 size)
{
    DLLIST *newNode;

    newNode = malloc(sizeof(*newNode));

    if (newNode != NULL)
    {
        newNode->previous = NULL;
        newNode->next = NULL;
        newNode->tag = tag;
        newNode->size = size;
        newNode->object = malloc(size);

        if (newNode->object != NULL)
        {
            memcpy(newNode->object, object, size);
        }
        else
        {
            free(newNode);
            newNode = NULL;
        }
    }

    return newNode;
}

事实上,作为初学者,这个功能的许多方面让我感到困惑:

  1. 为什么DLLIST指针是以这种方式返回的,而不是作为引用指针传递和修改?如果这样做,则可以释放返回值,作为报告函数成功/失败的状态字节。
  2. 为什么没有测试第二个参数以确保指针不是NULL?将空指针传递给memcpy肯定是一件非常糟糕的事情?

此外,强制模块中的所有功能使用相同的调用约定是否是常见的做法?例如,采取上述功能的双链接列表模块中的所有函数是否都符合status byte = function(argument list)?此外,验证所有值可能不正确的函数参数是否是常见的做法?例如,检查所有指针值以确保它们不是null?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-01-08 20:01:07

为什么DLLIST指针是以这种方式返回的,而不是作为引用指针传递和修改?如果这样做,则可以释放返回值,作为报告函数成功/失败的状态字节。

通过从外部传入的参数返回结果是一种非常不优雅和繁琐的做法,只有在没有其他方法时才应该使用。它要求调用方定义一个接收对象,它本身就已经很糟糕了。但最重要的是,由于需要额外的声明,所以不能在纯表达式中使用函数。

大多数情况下,如果您可以通过一个纯函数实现您的功能,那么它应该通过一个纯函数来实现。即函数参数为输入,函数返回值为输出。这正是你在这个案例中所看到的。

为什么没有测试第二个参数以确保指针不是NULL?将空指针传递给memcpy肯定是一件非常糟糕的事情?

好吧,没什么可争论的,做这样的测试总是个好主意。但是,测试的确切方法可能会有所不同,这取决于程序层次结构中函数的“级别”(从“低级”到“高级”)。它应该是一个只调试的断言吗?它是否应该是一个永久的断言(即受控中止,带有错误日志和“调用我可能”的消息)?这是否应该是一个运行时测试,意味着一些有意义的恢复策略?回答这个问题没有“一条真正的规则”。这是一个代码设计的问题。

在测试失败的情况下,是否应该对此函数执行有意义的故障安全策略?如果没有,那么低级别函数中的运行时测试将毫无意义。它只会干扰代码的噪音和浪费性能。如果这确实是一个“低级”函数,那么在这里使用if进行运行时测试是不合适的。更合适的是只调试的断言assert(object != NULL && size > 0)

还请注意,使object != NULL测试特别适合于dlCreate的细节是,object值被传递给库函数memcpy,该函数已知在出现空指针输入时会产生未定义的行为。如果代码没有使用memcpy,而是使用了一些专有的my_copy_data函数,那么断言object有效性的正确位置将是my_copy_data的内部。dlCreate函数本身并不真正关心object值的有效性。

票数 1
EN

Stack Overflow用户

发布于 2013-01-08 19:47:43

我不得不说,这都是相当主观的。

1)为什么DLLIST指针以这种方式返回,而不是作为引用指针传递和修改?如果这样做,则可以释放返回值,作为报告函数成功/失败的状态字节。

这在一定程度上是品味问题。我更喜欢将指针传递给函数,以便调用者管理内存,尽管返回动态分配的指针也是有效的。在某些情况下,它更好、更简单,这取决于API架构。无论哪种方式,返回值都可以用于成功/失败检查,因为返回NULL指针将指示失败。

2)为什么没有测试第二个参数以确保指针不是空的?将空指针传递给memcpy肯定是一件非常糟糕的事情?

这是许多C程序员的一种心态(至少我知道的那些人),这也反映了语言是如何构建的。在大多数C库中,每个函数都有一个契约,而不尊重它会调用未定义的行为。我很少费心检查传递给函数的NULL参数。当我这样做的时候,这是因为NULL指针改变了函数的行为,而不是因为我确保调用者尊重契约。有些人可能会说,它的性能更好--从性能和/或大小上看--因为它到处都节省了一些指令(尤其是在有限的硬件上,因为有C语言而出名),我这样做主要是为了不让我的代码到处都是空检查。你可以这样做,只要它有适当的文档。

此外,强制模块中的所有功能使用相同的调用约定是否是常见的做法?

我必须同意这一点。我不能代表别人说话,但我相信大家都认为这是个好做法。在同一个API中的函数之间切换调用约定可能会使程序员感到困惑,并让他们浪费时间反复检查文档。

此外,验证所有值可能不正确的函数参数是否是常见的做法?

这是很常见的,但相反的情况可能也很常见(参见上面的第2条)。

票数 2
EN

Stack Overflow用户

发布于 2013-01-08 20:05:10

回答问题1:返回值有三个常见的约定,您可以选择最适合您的应用程序:

  1. 返回状态值(int)。通常,负值表示错误,>=0成功。例如,POSIX "open()“函数。如果需要传递某个对象,则传递指向它的指针(用于"IN“参数,或指向指向它的指针的指针(用于"OUT”参数)。
  2. 对于“面向对象”函数,特别是对于分配某些内容的函数,返回一个指向对象的指针(如您给出的双链接列表示例中所示)。如果失败,则返回NULL。以POSIX "fopen()“为例。
  3. 绝对值函数这些值并不表示成功或失败,而是某种计算的实际结果(如"sin()")。

你可以根据自己的口味混合和搭配这些风格。许多图书馆都有一个混合体。尽量不要让API的用户不得不做扭曲才能使用它!

例如,如果您将API更改为

代码语言:javascript
运行
复制
int dlCreate(uint16 tag, void *object, uint32 size, DLLIST **list)

现在,用户有两种方法来判断文件是否被打开(查看退出状态,并查看已填充的列表指针),并且必须做大量额外的工作才能找出对错误正确的thiong操作。所以不要写

代码语言:javascript
运行
复制
DLLIST *list;
if ((list = dlCreate(tag, object, sz) == NULL) {
  // handle out of memeory error
  ...

用户不得不说

代码语言:javascript
运行
复制
DLList *list = NULL // must initializein this case
if (dlCreate(tag, object, sz, &list) == ERROR || list == NULL)  {
  if (list != NULL) {
    free(list);
  }
  // and other error handling as above

尽管如此,对于一个库来说,使用一致的风格往往是很好的做法。

回答问题2:这是草率的编程,你是对的;一个好的程序员应该永远不要相信调用者“做正确的事情”。始终添加代码来验证参数。如果你在这里传递了一个糟糕的指针,你就会崩溃!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14222721

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档