【问题标题】:can this code be optimized?这段代码可以优化吗?
【发布时间】:2011-08-22 05:34:06
【问题描述】:

我想我越来越痴迷于优化,所以我想知道以下代码是否可以“优化”:

假设我有一个 C 语言链表,在创建新元素时我使用以下代码:

log_event_list_cur->next = 
    (struct log_event_list *)malloc(sizeof(struct log_event_list));

log_event_list_cur = log_event_list_cur->next;

不知道下面的代码是否可以:

log_event_list_cur = 
    log_event_list_cur->next = 
        (struct log_event_list *) malloc(sizeof(struct log_event_list));

或:

log_event_list_cur->next = 
    log_event_list_cur=(struct log_event_list *) malloc....

问候!

【问题讨论】:

  • 如果你想让代码看起来更容易一些,你可以省略强制转换 - 在 C 中它是不必要的(也可能隐藏错误)。

标签: c list operators linked-list


【解决方案1】:

是的,第一个很好(与第一个代码行为等效的正确代码),但优化都不是。它们将被编译成相同的机器代码。做你认为最易读的事情。

第二个行为不同,因为log_event_list_cur 在设置next 之前被分配给一个新的列表条目。

【讨论】:

    【解决方案2】:

    它不会有任何区别。无论如何,简单的赋值都会被编译器优化掉。

    至少了解如何获取汇编代码的“要点”,以及如何从可执行文件中转储汇编输出。在 Linux 上,使用 objdump -S -d 将为您提供带有汇编程序的内联代码。

    【讨论】:

    • 太棒了,即使我几乎完全忘记了 assambler lang,我也会尝试一下。谢谢。
    【解决方案3】:

    正如已经指出的,编译器可能会为所有三个版本生成相同的代码。

    相反,如果您真的想让它更快,请实现一个空闲列表,即包含当前未使用的列表项的第二个列表。这样,“分配”一个新成员意味着只是从空闲列表中弹出一个项目(类似地“释放”意味着简单地将项目推到空闲列表中)。这样,您就没有每个​​新“分配”的 malloc/free 开销。显然,如果空闲列表为空并且您需要分配一个新成员,则无论如何您都必须调用malloc,但希望这种情况很少发生。

    顺便说一句,我希望你只是省略了对malloc 的返回值的检查。否则,如果malloc 返回 NULL,那么您很快就会崩溃……

    【讨论】:

    • 是的,我做到了.. 谢谢。这些节点仅在出现“硬”错误时才会转储到文件中,一旦创建,对这些节点的修改将永远不会发生。但是,您的观点似乎很有趣,可以用于其他列表。问候。
    • @user905292 如果它们也从未被读取,那么我建议避免使用内存列表并简单地 mmap() (空)转储文件,在编写新元素时根据需要对其进行扩展,并且成功完成后将其删除。
    • 好吧,由于硬错误不会经常发生,我决定采用这种方式来避免(我不知道如何命名...)开销?加班?每次运行该程序时将文件写入存储。您认为 mmap(我以前从未使用过)可以帮助我吗?
    • 在调用 sync() 之前,操作系统不需要将更改写入 mmap()ed 文件,因此您可以控制这种情况发生的频率。 mmap() 的好处是,如果数据变得非常大,它将由文件支持,而不是由交换空间支持。
    【解决方案4】:

    停止沉迷于优化,开始沉迷于可读性。 过早的优化是万恶之源。

    第一个代码片段没问题。很清楚发生了什么。链表在当前条目之后得到一个新条目(可能是最后一个条目),然后将当前条目向前移动成为最后一个。

    要理解第二个片段中发生的事情要困难得多。它最终与第一个示例相同,但需要付出脑力才能确保它确实如此。

    第三个片段全错了,它是一个完美的例子,说明为什么你甚至不应该在开始考虑优化之前就开始考虑优化。把它做好,然后让它变得快,只有当你亲眼看到冷酷的分析器数据时才做后者。

    【讨论】:

      【解决方案5】:

      正如其他答案中提到的,编译器应该能够优化您显示的任何差异;为了可读性,我可能会选择第一个,而且为了可读性,我可能会设置一个 #define (或在更高版本的 C 中设置一个 const ),其值为您的 sizeof 调用,以及您的 typedef struct 将大小压缩一点。

      [编辑:根据对该问题的评论,演员阵容甚至没有必要,已删除。]

      [编辑:根据对问题 sizeof(log_node) as a const 的另一条评论不再有意义;当它是c_log_node_sizesizeof(struct log_event_list) 时,它(有点)做到了,但现在它完全是愚蠢的。 (如评论中所述,还有其他很好的理由不这样做,也许 sizeof_c_log_node 可以吗?不不不。):D]

      typedef struct log_event_list log_node
      

      然后就变成了:

      log_event_list_cur->next = malloc(sizeof(log_node));
      log_event_list_cur = log_event_list_cur->next;
      

      如果您想对代码的这个特定部分进行一些优化,首先我建议您对系统进行一些分析,以确保它实际上是一个瓶颈。如果它没有引起问题,那么就不需要优化,你花在优化上的任何时间都最好花在其他地方,因为无论如何它都没有任何区别。可能有些东西可以使用优化,但可能不是这样。但是,考虑到这个特定的代码块,唯一想到的就是优化块的分配。

      我开始为此编写一些代码,但我没有离开它,因为我意识到根本没有必要在这个上重新发明轮子,除了它很有趣。如果您发现优化那段代码很有价值,这里是possibility for tweaking your allocations: vmalloc。除非你真的能证明它是一个瓶颈,否则我不会搞砸它。不过想想还是挺不错的。 :)

      【讨论】:

      • 你为什么要为此做一个常量?你把你的命名空间弄得乱七八糟,每个人都知道sizeof 是什么意思。我不知道c_log_node_size 是什么,我不想输入那么多,我无法相信我可能会推断出它是什么。 sizeof(log_node) 更清晰。
      • 好吧,当它仍然是sizeof(struct log_event_list) 时,它会缩短一些东西,然后当我简化其余部分时,我没有重新评估它的价值。是的,我同意sizeof(log_node) 好多了。事实上,我同意你所说的一切,除了 sizeof(log_node) 是 16 个字符和 c_log_node_size 是 15 个字符(如果你想添加这样一个事实,你必须按 shift in (_ 然后是 19 和 18)所以我不确定我是否得到了“那么多打字”的部分,因为你削减它c_log_node_size 的任何方式都比sizeof(log_node) 少打字(一个字符)。 ;)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-13
      • 1970-01-01
      • 2013-09-11
      • 1970-01-01
      相关资源
      最近更新 更多