C和C++中寄存器变量的地址

kun*_*l18 5 c c++ gcc g++ cpu-registers

我知道寄存器变量的概念和它的用例,但根据我的尝试,我脑子里几乎没有问题.

  1. 我不能在C中访问寄存器变量的地址,虽然我可以做C++!为什么?访问寄存器变量的寻址有什么问题吗?

  2. 假设我在C++中声明一个字符串变量作为寄存器,那么该变量将存储在哪里?在C++中声明非数字数据类型(如'string')的存储类是什么意义?

更新: 我认为C++允许我们获取寄存器变量的地址,因为我的程序中没有出现任何错误,如下所示:

#include<iostream>
#include<time.h>

using namespace std;

clock_t beg, en;

int main(){

    int j, k=0;

    beg=clock();
    for(register int i=0;i<10000000;i++){
        /*if(k==0){
            cout<<&i<<endl;    // if this code is uncommented, then C++ rejects the recommendation to make 'i' as register
            k++;
        }*/
    }
    en=clock();

    cout<<en-beg<<endl;

    cout<<&j<<endl<<&k;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我观察到的是,如果我将变量'i'作为寄存器并且不尝试使用'&i'来打印地址,那么C++接受推荐并将'i'存储在寄存器中,这可以从运行时间到for循环,如果'i'在寄存器中,则总是大约4-12 ms.但是,如果我尝试打印变量'i'的地址,那么虽然我没有得到任何错误,但C++拒绝推荐,这可以从执行循环的时间开始,如果我没有注册,总是超过25! !

所以,基本上我不能用C和C++中的存储类作为寄存器来获取变量的地址!为什么?

Ker*_* SB 17

C和C++是不同的语言.

  • 在C中,您不能使用register存储来获取变量的地址.参看 C11 6.7.1/6:

    具有存储类说明符的对象的标识符声明register 表明对对象的访问尽可能快.这些建议有效的程度是实施定义的.

    脚注:实施可以将任何register声明简单地视为auto声明.[...]

  • 在C++中,register是一个已弃用,无意义的关键字,它没有任何效果(除了可能充当编译器提示),并且声明的变量register仍然只具有自动存储.特别是,C++ 没有 "寄存器"存储类.(它只有继承自C 的存储类说明符.)C++ 11,7.1.1/3:

    一个register说明符是一种提示,如此声明的变量将被频繁使用的实现.[注意:提示可以忽略,在大多数实现中,如果采用变量的地址,它将被忽略.这个用途已被弃用[...]

用C甚至没有任何实际担保有关如何注册存储实现(实现可以自由治疗registerauto),但无论语言规则.

  • @stalin:我打电话给胡说八道.我刚刚与`g ++ -O3`进行了比较,两个版本都生成相同的代码.(虽然-O0有所不同.但是没有优化就可以说C++有什么用.如果你愿意的话,可以把`register`想象成一个本地化的编译器编译指示.) (8认同)
  • @stalin"你在说什么?" - 对Kerrek来说这不是一件好事,他非常了解."当我被宣布注册(并且我没有使用)时,我的代码如何显示出显着的时间改进?" - 它没有.生成asm代码并查看. (4认同)
  • @KerrekSB:感谢您在向我解释时的帮助和耐心。我为自己的行为道歉。你真的比我拥有更多的知识和经验,我当时真的在说屎! (2认同)
  • @stalin:不用担心:-)重要的是,您注意到了一些东西,并进行了测量,并希望了解更多信息。那总是一件好事。 (2认同)

Bil*_*nch 7

首先,我们来看看相关标准.C和C++总是有可能对此关键字有不同的含义.

C++ 2011第7.1.1节第2和第3段:

寄存器说明符应仅适用于块(6.3)中声明的变量名称或函数参数(8.4).它指定命名变量具有自动存储持续时间(3.7.3).在块作用域中声明没有存储类说明符或声明为函数参数的变量默认具有自动存储持续时间.

寄存器说明符是对实现的暗示,如此声明的变量将被大量使用.[注意:提示可以忽略,在大多数实现中,如果采用变量的地址,它将被忽略.不推荐使用此功能(参见D.2). - 结束说明]

C 2011第6.7.1节第6段和脚注121:

具有存储类说明符寄存器的对象的标识符声明表明对对象的访问尽可能快.这些建议有效的程度是实施定义的.)

实现可以将任何注册声明简单地视为自动声明.但是,无论是否实际使用了可寻址存储,使用存储类说明符寄存器声明的对象的任何部分的地址都无法显式(通过使用6.5.3.2中讨论的一元和运算符)或隐式计算(通过将数组名称转换为指针,如6.3.2.1中所述.因此,可以应用于使用存储类说明符寄存器声明的数组的唯一运算符是sizeof和_Alignof.

所以,让我们带走我们在这里学到的东西.

  • 在C++中,register关键字没有意义.它确实起到编译器提示的作用,但是建议大多数编译器无论如何都会忽略该提示.
  • 在C中,register关键字保留了含义.例如,在这里,我们不允许获取对象的地址(请参阅引用的脚注).实现可以忽略寄存器提示,并将对象放在内存中,但关键字确实限制了您可以对该对象执行的操作.这些限制应该使编译器能够更好地优化对象的访问,但是也可以(就像在C++的情况下建议的那样),编译器无论如何都能够推断出这一点.

至于你在实践中看到的是什么:

  • 当你试图获取a的地址时,我们可以看到为什么你在C中得到语法错误register int,所以让我们超越它.
  • 您声称在C++中看到性能差异取决于您是否使用register.在这种情况下,最好显示您的测试,因为测试本身可能存在问题.如果完整测试没问题,那么您的编译器肯定可能正在使用提示来生成更好的代码.
  • 你展示的代码肯定是奇怪的.那是因为优化下的编译器可能只是从代码中删除整个for循环.for循环没有副作用.很可能(和优选的),该编译器将返回相同的代码(即,没有代码)与for (int i=0; i<100; ++i){}for (register int i=0; i<100; ++i) {}.