Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C K&;R将练习问题转换为关于原始问题的答案_C_Macros_Function Calls - Fatal编程技术网

C K&;R将练习问题转换为关于原始问题的答案

C K&;R将练习问题转换为关于原始问题的答案,c,macros,function-calls,C,Macros,Function Calls,我一直在努力寻找K&R问题7-8的解决方案,直到我在这个网站上找到了答案。我无法对答案发表评论(可能是因为它的年龄);在这个问题上,我唯一能真正获得意见的方法就是发布一个答案,我觉得这是不合适的。因此,我决定根据所选的“答案”创建一个高度相关的问题,这对我来说似乎是合乎逻辑的,直到我说到这一点(关于将函数实现为宏): “经常以宏的形式重复这一点,“节省空间”很快成为成本,因为位屏蔽具有固定的大小。” 唯一的问题是函数调用也需要时间。“跳转”到函数位置,为局部变量留出存储空间,然后实际计算比较,所

我一直在努力寻找K&R问题7-8的解决方案,直到我在这个网站上找到了答案。我无法对答案发表评论(可能是因为它的年龄);在这个问题上,我唯一能真正获得意见的方法就是发布一个答案,我觉得这是不合适的。因此,我决定根据所选的“答案”创建一个高度相关的问题,这对我来说似乎是合乎逻辑的,直到我说到这一点(关于将函数实现为宏):

“经常以宏的形式重复这一点,“节省空间”很快成为成本,因为位屏蔽具有固定的大小。”

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

那么,实现一个测试字符ASCII值的宏要比第一个包含查表功能的宏慢多少呢

一个函数调用比比较两个整数(其中一个已经在内存中,另一个是常量)花费的时间要少,这怎么可能呢?在我看来,随着时间的推移,反复调用函数和宏仍然会导致宏速度加快

我的思维方式错了吗?我想应该是,因为它不是在最初的问题中提出来的


如果有人能解释一下,我会很高兴的。

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

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

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

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


当然,如果在紧循环中仅执行该宏,则宏也将在大部分时间处于缓存中。当您从代码中足够多的不同位置调用该函数时,该函数的优势就会出现,即使在循环的第一次迭代中,它通常也会在缓存中,而宏通常不会这样做。

谢谢您的回答。最初的问题暗示有不同的选择,要么节省空间,要么节省时间(我认为这意味着速度)。放弃循环(尽管在这个意义上你是正确的),让我们来谈谈手头的函数(isupper)。假设对这个函数的调用是随机的,分散在整个程序中(这样它的代码就不会在缓存中),考虑到调用“实”函数的时间,纯函数实现(实现表查找)会比宏(实现ASCII比较)快吗,或者会是另一种情况吗?@Kevin,如果函数很少被使用,以致于将其描述为“稀疏分散”,那么它几乎肯定不是瓶颈,甚至不是对运行时间的显著贡献。小心不要落入过早优化的陷阱。@Kevin,该函数还有另一个优点。这是一个标准的库例程,在现代系统上由DLL或.so提供。这意味着包含此函数及其查找表的页面可以在物理内存中存在一次,但可以被任意数量的进程使用。一个进程中的性能可能会受到所有其他进程的影响,这些进程会对其进行搔痒,将页面保留在物理内存中,甚至可能将相关位保留在缓存中。这可能很难分析。@RBerteig:谢谢你的分析。我很清楚,函数实现显然是“真实世界使用”的正确方式,但我更多的是指某种“实验室测试”,它只是比较两种选择,而没有缓存和其他过程等因素(我相信这也是K&R问题的目的)。我想我想要的是:“纯粹的函数,即使有调用时间,也比ASCII比较快”,但我不明白这怎么可能是真的。尽管如此,还是有很好的答案。欢迎有更多想法!