指针可能指向cpu寄存器吗?

时间:2010-10-14 20:15:18

标签: c++ optimization pointers reference

我想知道指针是否指向cpu寄存器,因为在它可能没有的情况下,使用引用而不是指针尽可能使编译器有机会进行一些优化,因为引用的对象可能驻留在某个寄存器中但是指针指向的对象可能不会。

7 个答案:

答案 0 :(得分:9)

一般来说,CPU寄存器没有内存地址,虽然CPU架构可以使它们可寻址(我不熟悉任何 - 如果有人知道,我会很感激评论)。但是,C中没有标准的方法来获取寄存器的地址。实际上,如果使用register存储类标记变量,则不允许使用&运算符来获取变量地址。

关键问题是别名 - 如果编译器可以确定对象没有别名,那么它通常可以执行优化(无论是通过指针还是引用访问对象)。我不认为你会使用指针上的引用获得任何优化好处(通常无论如何)。

但是,如果将对象复制到局部变量中,那么编译器可以更容易地确定本地没有别名,假设您没有传递临时地址。这是一个可以帮助编译器优化的情况;但是,如果复制操作很昂贵,最终可能无法获得回报。

对于适合CPU寄存器的东西,复制到temp通常是一种好方法 - 编译器非常善于优化寄存器。

答案 1 :(得分:3)

当引用传递给函数时,编译器可能会将其实现为隐藏指针 - 因此更改类型无关紧要。

当在本地创建和使用引用时,编译器可能足够聪明以了解它所引用的内容并将其视为引用变量的别名。如果变量针对寄存器进行了优化,则编译器会知道该引用也是同一个寄存器。

指针始终需要指向内存位置。即使在为其寄存器提供存储器位置的奇数架构上,编译器似乎也不太可能支持这种操作。

编辑:例如,以下是Microsoft C ++生成的代码,并进行了优化。指针的代码和传递的引用是相同的。由于某种原因通过值传递的参数不会在寄存器中结束,即使我重新排列参数列表也是如此。即便如此,一旦将值复制到寄存器,本地变量和本地引用都使用相同的寄存器而不重新加载它。

void __fastcall test(int i, int * ptr, int & ref)
{
_i$ = 8                         ; size = 4
_ref$ = 12                      ; size = 4
?test@@YIXHPAHAAH@Z PROC                ; test, COMDAT
; _ptr$ = ecx

; 8    :    global_int1 += *ptr;

    mov edx, DWORD PTR [ecx]

; 9    : 
; 10   :    global_int2 += ref;

    mov ecx, DWORD PTR _ref$[esp-4]
    mov eax, DWORD PTR _i$[esp-4]
    add DWORD PTR ?global_int1@@3HA, edx    ; global_int1
    mov edx, DWORD PTR [ecx]
    add DWORD PTR ?global_int2@@3HA, edx    ; global_int2

; 11   : 
; 12   :    int & ref2 = i;
; 13   :    global_int3 += ref2;

    add DWORD PTR ?global_int3@@3HA, eax    ; global_int3

; 14   : 
; 15   :    global_int4 += i;

    add DWORD PTR ?global_int4@@3HA, eax    ; global_int4

答案 2 :(得分:2)

我认为您的意思是引用所引用的整数值是否存在于寄存器中。

通常,大多数编译器以与指针相同的方式处理引用。也就是说,引用只是内置特殊“dereference”语义的指针。所以,遗憾的是,与可以适合寄存器的整数值不同,通常没有优化。引用和指针之间的唯一区别是引用必须(但不是由编译器强制执行)引用有效对象,而指针可以为NULL。

答案 3 :(得分:1)

在许多(如果不是大多数或全部)实现中,引用是通过指针实现的深层内部。所以我认为通过指针或引用来实现它与优化器几乎无关。

答案 4 :(得分:1)

我会说一般不会。正如上面的评论中所提到的那样,有一些处理器可以在内存空间中寻址寄存器,但这可能是一个坏主意(除非芯片是为你设计的那样设计的。)

这更像是你实际发生的事情的反面。优化器可以看到你正在用指针做什么以及它指向什么,并且取决于体系结构可能实际上不使用指针寄存器和寄存器来保存它指向的内容但是例如可以使用硬编码地址到指令中根本没有登记册。可以将指向的值加载到寄存器中,但使用寄存器作为地址,或者使用的时间长于获取值所需的时间。有时它不是那么有效,它可以将寄存器中的值保存为ram,这样它就可以使用其地址将其读回寄存器,当更改代码时可以避免这两步。它在很大程度上取决于程序/代码以及指令集和编译器。

因此,不要试图寻址寄存器以尝试进行一些优化,而是知道编译器和目标,并知道何时使用指针或数组或值等更好。某些构造在大多数处理器上运行良好,有些只能正常工作很好,但其他人很糟糕。

答案 5 :(得分:0)

指针指向内存位置。因此无法使用指针访问CPU寄存器。引用是指针不太强大的版本(你不能对引用执行算术)。然而,编译器通常将变量放入寄存器以执行操作。例如,编译器可以将循环计数器放入其中一个CPU寄存器中以便快速访问。或者可以放置在寄存器中不占用太多空间的函数参数。 C中有一个关键字,可用于请求编译器将某个变量放入CPU寄存器。关键字为register

for (int i = 0; i < I; i++)
    for (int j = 0; j < J; j++)
        for (register int k = 0; k < K; k++)
        {
            // to do
        }

答案 6 :(得分:0)

迈克尔伯尔是对的。 CPU寄存器没有内存地址。