我将一个指针传递给一个指向 function x
的指针,我对该指针进行一些处理,然后释放 function y
上的值
int x(char **str) {
/* do some processing */
return 0;
}
int y () {
char *str;
x (&str);
/* do some processing */
free (str);
}
但是,我注意到如果我将 str
声明为 global
,那么程序完成所有操作所花费的时间少于实际传递 str
周围。一个需要 135 秒和 139 秒
(包括上面未编码的所有处理)
所以,我想知道为什么将指针传递给指针可能比使用全局方法“明显”慢。
注意:我测试了几次,给出了与上述相同的结果。
谢谢
最佳答案
我很好奇你是如何计算时间的,因为一般来说,双重间接寻址的成本不会比单一间接寻址高多少——差异应该很小。
但是,如果在这种情况下您的双指针确实比单个指针花费更多,有两个可能的原因:
(1) Pipeline潜伏。
现代 CPU 的设计方式是,虽然它们每个周期可以执行(至少)一条指令,但大多数指令需要一个以上的周期才能完成。也就是说,您可以在每个时钟周期开始一个新的“加法”操作,但是任何给定加法的结果可能要等到您启动它的四个周期后才能获得。如果您尝试在操作准备就绪之前使用该操作的结果,则会导致称为 data hazard 的错误。 ,这仅仅意味着处理器必须等到结果准备好才能用它做其他事情。在您的情况下,计算机必须按顺序执行两个“加载”操作,装配如下:
load r3, str ; load the value of "str" (an address of a pointer) into register three
load r4, r3 ; load the thing at the address stored in r3 and put it in r4.
; in this case, r3 points at a char *, so the thing in r4 is also an address.
load r5, r4 ; load the thing at address r4 and put it in r5. that is your char.
在这种情况下,您可以看到第三次加载取决于第二次加载的结果,而第二次加载又取决于第一次。如果第二个加载需要一个以上的周期才能完成(几乎总是如此——通常五个周期大约是最佳情况下的延迟),那么第三个加载必须等待。管道中会出现“泡沫”。如果 str 是全局的,那么你的负载就少了一个,因此气泡也少了一个。
(2) Data cache
现代内存如此巨大,CPU 速度如此之快,以至于从 CPU 访问主 RAM 可能需要很多很多周期。为了加快速度,CPU 在本地缓存中存储较小的主内存子集,因为如果您使用变量 x,很可能您将使用 x 或又在 x 附近了。访问缓存很快,但它只存储少量数据——通常在 256kb 到 4mb 之间。如果加载操作试图访问不在高速缓存中的地址,则 CPU 必须一直到主 RAM 获取它,并且加载操作可能需要 1000 个周期而不是五个。
因此,如果访问 **str 意味着两次缓存未命中而不是一次,那么差异可能很大。
Ulrich Drepper 在他的论文 What Every Programmer Should Know About Memory 中对所有这些问题做了很好的解释.
关于c - 在C中将指针传递给指针的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4242474/