【问题标题】:C functions overusing parameters?C函数过度使用参数?
【发布时间】:2009-03-31 04:25:40
【问题描述】:

我有遗留的 C 代码库在工作,我发现很多函数实现都采用以下风格。

char *DoStuff(char *inPtr, char *outPtr, char *error, long *amount)
{
    *error = 0;
    *amount = 0;

    // Read bytes from inPtr and decode them as a long storing in amount
    // before returning as a formatted string in outPtr.

    return (outPtr);
}

使用 DoStuff:

myOutPtr = DoStuff(myInPtr, myOutPtr, myError, &myAmount);

我觉得这很迟钝,当我需要实现类似的功能时,我最终会这样做:

long NewDoStuff(char *inPtr, char *error)
{
    long amount = 0;
    *error = 0;

    // Read bytes from inPtr and decode them as a long storing in amount.

    return amount;
}

使用 NewDoStuff:

myAmount = NewDoStuff(myInPtr, myError);
myOutPtr += sprintf (myOutPtr, "%d", myAmount); 

我不禁想知道我在上面的示例中是否缺少某些东西,是否有充分的理由使用这种方法?

【问题讨论】:

  • += sprintf 是什么?
  • msdn.microsoft.com/en-us/library/ybk95axf(VS.71).aspx 写入字符串,然后将指针向前移动已写入的字节数。
  • 不应该是 = 而不是 +=?
  • 没有。 sprintf 返回写入的字节数。我想在 sprintf 调用之后将 char* 指针向前移动那么多字节,以便下一个 sprintf 调用充当附加。在上面的 MSDN 链接中有类似的例子。

标签: c


【解决方案1】:

一个优点是,如果您在代码中对这些函数进行了很多次调用,那么一遍又一遍地重复调用sprintf 很快就会变得乏味。

此外,返回 out 指针可以让您执行以下操作:

DoOtherStuff(DoStuff(myInPtr, myOutPtr, myError, &myAmount), &myOther);

使用您的新方法,等效代码要冗长得多:

myAmount = DoNewStuff(myInPtr, myError);
myOutPtr += sprintf("%d", myAmount);
myOther  = DoOtherStuff(myInPtr, myError);
myOutPtr += sprintf("%d", myOther);

【讨论】:

    【解决方案2】:

    它是 C 标准库风格。返回值有助于链接函数调用。

    另外,DoStuff 更清洁 IMO。你真的应该使用snprintf。缓冲区管理内部结构的更改不会影响您的代码。但是,NewDoStuff 不再适用。

    【讨论】:

    • 缓冲区管理内部的变化是什么意思?我相信这两种方法的所有指针最终都是一样的,尽管我可能是错的。
    • @sipwiz:我假设DoStuff 负责“myOutPtr += sprintf (myOutPtr, "%d", myAmount);"部分。这促使了上述说法。
    【解决方案3】:

    您提供的代码有点不清楚(例如,您为什么要在 sprintf 的结果中添加 myOutPtr。

    但是,总的来说,您所描述的本质上似乎是将一个执行两件事的函数分解为一个执行一件事的函数和一个执行其他操作的代码(串联)。

    将职责分成两个功能是个好主意。但是,您可能希望为这种连接和格式设置一个单独的函数,这真的不清楚。

    此外,每次将函数调用拆分为多个调用时,都会创建代码复制。代码复制从来都不是一个好主意,因此您需要一个函数来执行此操作,并且您最终会得到(这是 C)看起来像原始 DoStuff 的东西。

    所以我不确定你能做些什么。非 OOP 语言的限制之一是您必须发送大量参数(除非您使用结构)。你可能无法避免巨大的界面。

    【讨论】:

      【解决方案4】:

      如果您在每次调用 NewDoStuff 后都必须执行 sprintf 调用,那么您就是在重复自己(因此违反了 DRY 原则)。当您意识到需要以不同的方式对其进行格式化时,您将需要在每个位置进行更改,而不仅仅是一个位置。

      【讨论】:

        【解决方案5】:

        根据经验,如果我的某个函数的接口超过 110 列,我会强烈建议使用结构(如果我正在采用最好的方法)。我(永远)不想做的是采用一个可以做 5 件事的函数并将其分解为 5 个函数,除非函数中的某些功能不仅有用,而且需要单独使用。

        我更喜欢第一个函数,但我也很习惯标准的 C 风格。

        【讨论】:

          猜你喜欢
          • 2016-06-19
          • 1970-01-01
          • 2013-08-28
          • 2011-09-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多