2

我一直在尝试解决 K&R 问题 7-8 的解决方案,直到我在这个站点上找到了这个解决方案(带有原始问题) 。我无法评论答案(可能是由于它的年龄);我实际上可以对该问题提出意见的唯一方法是发布答案,我认为这是不合适的。因此,我决定根据所选的“答案”创建这个高度相关的问题,这对我来说似乎是合乎逻辑的,直到我到了这一点(关于将函数实现为宏):

“经常重复这一点,因为位掩码具有固定大小,因此‘节省空间’迅速成为成本。”

唯一的问题是函数调用也需要时间。“跳转”到函数位置,为局部变量留出存储空间,然后实际计算比较,都需要时间。

那么究竟是如何实现一个宏来测试字符的 ASCII 值比第一个包含表查找的函数慢(考虑到这一点)?

一个函数调用怎么可能比比较两个整数花费更少的时间,其中一个整数已经在内存中,其中一个是常量?在我看来,随着时间的推移,重复调用函数和宏仍然会导致宏更快。

难道我的思维方式不对?我认为它必须是因为它没有在原始问题中提出。

如果有人能对此有所了解,我会很高兴。

4

1 回答 1

3

首先,请注意他们提到的成本是大小,而不是速度。例如,假设宏扩展为 16 字节的代码。让我们进一步假设该函数编译为 32 个字节的代码,调用该函数需要 6 个字节的代码(当然,这些都不能保证,但它们都可能至少在 32 位正确的一般范围内代码)。

在这种情况下,如果你使用一个函数,但只从一个地方调用它,你最终会得到 38 个字节的代码。如果您改用宏,您只会得到 16 个字节的代码,从而节省 22 个字节。如果您在两个地方使用宏,您将获得 32 字节的代码,而如果您使用函数则为 44 字节——仍然是一种节省,但更小。稍微向前一点,假设您在代码中的 10 个不同位置使用了它。在这种情况下,宏将占用 160 个字节,但函数仅占用 92 个字节。

在现代处理器上,我还可以看到一个相当合理的论点,即函数也可以更快。大多数现代处理器都使用缓存。如果你使用的函数足够多,当你调用它时它通常会在缓存中,这可能比使用宏更快,每次使用代码时,你(更多)可能必须获取再次从内存中编码。原因很简单:现代处理器的运行速度内存快得多。

即使充其量,您也可以计划至少 50 ns 的延迟来从内存中获取一些数据(并且 75-100 ns 相当普遍)。就像平均值一样,我们假设 75 ns。典型的现代 CPU 每个时钟执行大约 1.8 条指令,在(比如说)2.5 GHz 时,时钟周期时间为 0.4 ns。这意味着在 75 ns 内,它可以(平均)执行 75/0.4*1.8 = 337.5 条指令。从我们这里讨论的函数调用、执行和返回大约有六条指令——所以在一个紧密的循环中,当你从内存中获取宏的代码时可以从缓存中执行该函数大约 56 次。

当然,如果你只是在一个紧密的循环中执行它,那么宏也将在大部分时间都在缓存中。当您从代码中足够多的不同位置调用该函数时,该函数的优势就会发生,即使在循环的第一次迭代时,它通常也会在缓存中而宏通常不会出现这种情况。

于 2010-11-04T07:00:12.903 回答