繁体   English   中英

使用函数参数作为变量

[英]Using function parameter as variable

在函数内部重新分配函数参数是不好的做法还是好的做法,或者是不确定的行为?

让我用一个例子来说明我要做什么:

void
gkUpdateTransforms(GkNode *node /* other params */) {
  GkNode *nodei;

  if (!(nodei = node->chld))
    return;

  do {
    /* do job */
    nodei = nodei->next;
  } while (nodei);
}

选择:

void
gkUpdateTransforms2(GkNode *node /* other params */) {

  /* node parameter is only used here to get chld, not anywhere else */
  if (!(node = node->chld))
    return;

  do {
    /* do job */
    node = node->next;
  } while (node);
}

我检查了程序集的输出,看起来好像一样,我们不需要在第二个中声明一个变量。 您可能会问,如果更改了参数类型,但是对于第一个参数,相同的条件将是相同的,因为它也需要更新。

编辑:参数是按值传递,我的意图不是编辑指针本身

EDIT2:递归函数呢? 如果gkUpdateTransforms2是递归的,会发生什么? 我很困惑,因为函数会自行调用,但我认为在每次调用中,参数都会不同

我不知道您为什么认为这将是未定义的行为-事实并非如此。 通常,这只是编码风格的问题,没有明显的对与错。

通常,优良作法是将参数视为不可变对象 保留功能的原始输入副本是很有用的。 因此,最好使用局部变量,该局部变量只是参数的副本。 如您所见,这丝毫不影响性能-编译器将优化代码。

但是,如果您也写入参数,则没什么大不了的。 这也是常见的做法。 称其为不良做法将非常令人讨厌。

如果不应该修改某些函数式编码样式,则所有函数参数都将变为const ,但我个人认为这只是混淆,这会使代码更难阅读。 在您的情况下,这种学究式样式将为void gkUpdateTransforms(GkNode*const node) 不要与const正确性相混淆,const正确性是一件普遍的事情,而不仅仅是样式问题。


但是,您的代码中确实存在某些绝对不正确的做法,那就是在条件内部进行赋值。 尽可能避免这种情况,这很危险,并使代码更难阅读。 大多数情况下没有好处。

在C的历史早期就注意到混合===的危险。为了解决这一问题,在1980年代,人们想到了诸如“尤达条件”之类的对大脑造成伤害的事物。 然后在1989年左右出现了Borland Turbo C,它具有精美的警告功能“可能错误分配”。 那是Yoda条件的死亡,从那时起,编译器就警告不要指定条件。

确保当前的编译器对此发出警告。 也就是说,请确保不要使用比1989年的Borland Turbo更差的编译器。是的,市场上有较差的编译器。

(gcc给出了“警告:建议将用作真值的赋值括号括起来”)


我将代码写为

void gkUpdateTransforms(GkNode* node /* other params */) 
{
  if(node == NULL)
  {
    return ;
  }

  for(GkNode* i=node->chld; i!=NULL; i=i->next;)
  {
    /* do job */
  }
}

这主要是风格上的更改,以使代码更具可读性。 它不会大大提高性能。

恕我直言,这不是完全“坏”的做法,但是值得怀疑的是,没有更好的方法。 关于分析汇编程序输出:它可能是有趣而有教育意义的外观,但是不建议您使用它作为优化或更糟的源代码懒惰的理由。 下一个编译器或下一个体系结构可能只会使您的想法完全无效-我的建议是在这里与Knuth保持联系: “与其想象我们的主要任务是指导计算机做什么,不如让我们专注于向人类解释我们想让计算机做什么。”

在您的代码中,我认为决定是50:50,没有明确的获胜者。 我认为节点迭代器有一个自己的概念,可以证明一个单独的编程结构(在我们的例子中只是一个变量)是合理的,但是函数又是如此的简单,以至于在下一个方面,我们并没有赢得太多程序员查看您的代码,因此我们可以很好地使用第二个版本。 如果您的功能开始随着时间的推移而变异和增长,则此前提可能会失效,我们最好选择第一个版本。 也就是说,我会像这样编写第一个版本:

void
gkUpdateTransforms(GkNode *node /* other params */) {    
  for (GkNode *nodei = node->chld; nodei != NULL; nodei = nodei->next) {
      /* do job */
  }
}

这是定义明确的,也是实现此行为的完美方法。

您可能将其视为问题的原因是执行以下操作的常见错误:

int func(object a) {
    modify a // only modifying copy, but user expects a to be modified

但是对于您的情况,您希望复制该指针。

只要按值传递它,就可以将其安全地视为任何其他局部变量。 在这种情况下,这不是一个坏习惯,也不是未定义的行为。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM