我想我已经沉迷于优化,所以我想知道以下代码可以“优化”:
假设我有一个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....
问候!
答案 0 :(得分:5)
是的,第一个很好(正确的代码行为与第一个代码相同),但两者都不是优化。它们将被编译为相同的机器代码。做你觉得最可读的事情。
第二个行为不同,因为在log_event_list_cur
设置之前next
被分配到新的列表条目。
答案 1 :(得分:1)
它不会有任何区别。无论如何,编译器将优化简单的赋值。
至少了解如何获得汇编代码的“要点”,以及如何从可执行文件中转储汇编输出。在Linux上,使用objdump -S -d
将为您提供带汇编程序的内联代码。
答案 2 :(得分:1)
正如已经指出的那样,编译器可能会为所有三个版本发出相同的代码。
相反,如果你真的想让它更快,那就实现一个空闲列表,即保存当前未使用的列表项的第二个列表。这样,“分配”新成员意味着只是将项目弹出自由列表(类似地“释放”意味着简单地按下空闲列表上的项目)。这样,每个新的“分配”都没有malloc
/ free
开销。显然,如果自由列表为空并且您需要分配一个新成员,那么无论如何都必须调用malloc
,但希望这种情况很少发生。
顺便说一下,我希望你省略了对malloc
的返回值的检查。否则,如果malloc
返回NULL,那么很快就会发生崩溃......
答案 3 :(得分:0)
正如其他答案中所提到的,编译器应该能够优化任何差异,例如你展示的;我可能会选择第一个用于提高可读性,并且为了便于阅读,我可能要么设置一个#define
(或者在{C}的更高版本中使用const
),并使用sizeof调用的值,并且你的struct的typedef可以稍微压缩一下。
[编辑:根据对问题的评论,甚至不需要删除演员阵容。]
[编辑:根据对sizeof(log_node)问题的另一个评论,作为一个const根本不再有意义;当c_log_node_size
对sizeof(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。除非你能真正证明它是一个瓶颈,否则我不会惹它。尽管如此,还是有点考虑。 :)
答案 4 :(得分:0)
不再沉迷于优化,开始沉迷于可读性。 过早优化是万恶之源。
第一个代码片段没问题。很明显发生了什么。链接列表在当前的一个之后获得一个新条目(可能是最后一个),然后当前向前移动成为最后一个。
要理解第二个片段中发生的事情要困难得多。它与第一个例子最终是一回事,但是人们需要运用精神上的努力来确保它真的存在。
第三个片段都是错误的,这就是为什么你不应该开始考虑在开始之前考虑优化的原因。做得对,然后让它快速,只有在你自己的眼前才有冷酷的分析数据才能做到这一点。