C:寄存器或存储器上的地址?

时间:2018-05-11 16:46:56

标签: c pointers processor

我对C中的关键词“注册”感到有点困惑。 它似乎告诉编译器它应该存储在一个寄存器中,这意味着我的一些变量存储在寄存器中,一些存储在内存中?如果是这样,有没有办法找出我的值是存储在寄存器还是存储器中?

例如:

int *x =  (int*) 0x1234;

X现在似乎没有指向寄存器,因为这些地址用于存储器。 但我已经多次尝试找到一个不同的寻址地址(也使用“寄存器”关键字)。即使在互联网上也没有人关心。

所以我的主要问题是:当指针指向寄存器时,指针中的地址如何显示?

编辑:我在另一个问题的结尾处找不到我的主要问题的答案。我的问题不是关键词“注册”,我刚才提到过。

4 个答案:

答案 0 :(得分:1)

  

当指针指向寄存器时,指针中的地址如何显示?

指针是内存的概念,寄存器没有地址。每个处理器都有一个有限的,固定数量的寄存器(可能是8-16)。

正如其他人所提到的,register不再有用,甚至有时会被编译器忽略。

要了解真正的寄存器,请考虑以下示例:

int a = k / 53;  // k is an int defined somewhere else...
int b = a * 9;
// a is not used after the above line

现在,我们尚未使用a声明register,但任何合理的编译器仍会保留在寄存器中。

这样做的原因是要执行任何操作,操作数必须在某些寄存器中。然后,操作的结果将是例如。存储在第一个操作数的寄存器中。

为了从上面的例子中计算a,编译器会编写代码将k(可能是在内存中)加载到某个寄存器中(让我们称之为寄存器A )和53到另一个。计算完成后,寄存器A将包含操作的结果。因为无论如何我们要在下一行中将结果乘以9,我们可以保持原样,将9加载到另一个寄存器中并乘以。将值存储到内存然后将其加载到寄存器中只会浪费很多时间。

请注意,使用a声明volatile会阻止此类优化并强制编译器实际存储和加载a。 (虽然volatile在这里对这个例子没有任何意义,但是如果不这样做,则几乎没有用,例如,接口特殊的硬件。)

答案 1 :(得分:1)

存储类说明符 register是在 C 语言的第一个版本上创建的,用于指示编译器使用其中一个处理器寄存器来保存具有允许更快访问的范围。那时代码编写需要程序员的大量关注,因为编译器不是那么聪明地检测错误或纠正它们导致错误的代码。

无论如何,在成长过程中,C标准得到了一些难以理解某些细节的技巧。

存储类说明符register就是其中之一。因此,让我们先看看规格,然后对它们进行评论。

来自 ISO / IEC 9899:2011 ,C11标准:

  

§6.7.1存储类说明符

     

对象的标识符声明   存储类说明符寄存器建议访问该对象   尽可能快地。这些建议的程度   有效是实现定义的。 (见注119)

注意事项119:

  

注意

     

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

这意味着存储说明符register是编译器的建议,以使用处理器寄存器或任何其他方法尽可能快地进行变量访问,但编译器可以采用一个不同的决定。它可以将声明的变量视为标准auto变量。

在最后一种情况下,技术上可以获得存储地址,但标准明确禁止这一点,如说明中所述,但也强制执行§的约束 6.5.3.2地址和间接运算符

  

一元&运算符的操作数应该是一个函数   指示符,[]或一元*运算符的结果,或者是左值   指定一个不是位字段的对象,并且未声明   register存储类说明符

当然,一些不合规的编译器可能允许您应用运算符。

现在回到你的问题:

  1.   

    int *x = (int*) 0x1234; X现在似乎没有指向寄存器,   因为这样的地址是为了记忆。但我已多次尝试过   查找不同的查找地址(也使用“注册”关键字)。   即使在互联网上也没有人关心。

  2. 您的示例错误,您正在声明指向int的指针并为其分配任意地址。这与register存储说明符无关。

    声明register int *x = (int*) 0x1234;,然后尝试将&运算符应用于x int **pp = &x;,注意我们正在声明指向{{1}的指针这就是我们得到指向int)的地址。

    兼容编译器会出错。

    1.   

      所以我的主要问题是:指针中的地址如何显示   登记册上的点?

    2. 答案很简单:它不像任何东西,因为它不能存在于标准C 中。

答案 2 :(得分:0)

在现代编译器中,您在C中声明的对象不一定只有一个存在的位置。为了优化您的程序,编译器可能会在某些时候将其保留在寄存器中,在其他位置的堆栈中或在其他位置的特定内存位置中。通常,您不需要知道哪个。

当您获取对象的地址并使用指针时,编译器会使您的程序工作,就好像该对象具有固定地址一样。通常这是通过将对象放在指定的内存位置来完成的,至少在您使用其地址的持续时间内,但允许编译器通过其他方式实现程序的最终结果。

如果使用register声明对象,则不应按C标准获取其地址。但是,一些编译器可能允许这样做。

答案 3 :(得分:0)

在大多数体系结构中,您不能指向CPU寄存器,因为它们不是内存映射的。 (8051是我能想到的一种架构,核心寄存器 内存映射的位置)。

另一方面,如果您指的是外设寄存器;这些内存映射并在地址空间中有地址,声明就像你拥有它一样 - 除了你需要volatile类型修饰符。

volatile int* x =  (volatile int*)0x1234 ;

register关键字与内存映射外设寄存器无关。