address of register variable in C and C++
C and C++ are different languages.
In C, you cannot take the address of a variable with
register
storage. Cf. C11 6.7.1/6:A declaration of an identifier for an object with storage-class specifier
register
suggests that access to the object be as fast as possible. The extent to which such
suggestions are effective is implementation-defined.Footnote: The implementation may treat any
register
declaration simply as anauto
declaration. [...]In C++,
register
is a deprecated, meaningless keyword that has no effect (except perhaps serve as a compiler hint), and variables declared asregister
still just have automatic storage. In particular, C++ doesn't have a "register" storage class. (It just has the storage class specifier, inherited from C.) Cf. C++11, 7.1.1/3:A
register
specifier is a hint to the implementation that the variable so declared will be heavily used. [ Note: The hint can be ignored and in most implementations it will be ignored if the address of the variable is taken. This use is deprecated [...]
Even in C nothing is actually guaranteed about how register storage is implemented (implementations are free to treat register
as auto
), but the language rules apply regardless.
Address of register variable
Here's an excerpt from Section 6.7.1 (footnote 101) of the C99 standard (pdf):
The implementation may treat any
register
declaration simply as anauto
declaration. However, whether or not addressable storage is actually used, the address of any part of an object declared with storage-class specifier register cannot be computed, either explicitly (by use of the unary&
operator as discussed in 6.5.3.2) or implicitly (by converting an array name to a pointer as discussed in 6.3.2.1). Thus, the only operator that can be applied to an array declared with storage-class specifierregister
issizeof
.
And from Section 7.1.1, Paragraph 3 of the C++ standard (pdf):
A
register
specifier has the same semantics as anauto
specifier together with a hint to the implementation that the object so declared will be heavily used. [Note: the hint can be ignored and in most implementations it will be ignored if the address of the object is taken. —end note]
Fun tidbits about register
The C++ group (WG21) wants to deprecate register
:
The
register
keyword serves very little function, offering no more than a hint that a note says is typically ignored. It should be deprecated in this version of the standard, freeing the reserved name up for use in a future standard, much likeauto
has been re-used this time around for being similarly useless.Notes from the March, 2009 meeting:
The consensus of the CWG was in favor of deprecating
register
.
Look what the C99 group (WG14) said about register
(pdf) at a meeting:
General agreement to deprecate the “
auto
” keyword. Should we ask WG21 to go back to
the previous use of “register
” (no address)? No, this will not fly with WG21.
Address of a variable stored in a register
First, the C Standard prohibits taking the address of a variable that is declared register
, just as it does for bit fields in struct
s.
For non-register ("auto") variables, the short answer is yes. The simplest strategy of an optimizer is to immediately spill variables whose addresses are taken.
"Spill" is just a term from the literature of register allocation meaning "decide to place in memory rather than a register."
A sophisticated optimizer can do an alias analysis and still hold a value in a register, even though its address has been taken. This is possible wherever it can be proven that the resulting pointer can't possibly be used to change the value.
Another relevant optimization is live range splitting. This allows a variable to be stored in a register for part of the range of instructions where it's holding a useful value (its "live range") and to be spilled in other parts. In this case the spilled parts would correspond to places where the pointer might be used to change the variable's value. For example:
x = 3;
... lots of computations involving x
if T {
// SPILL HERE, so store register holding x to memory
int *p = &x;
... lots of computations, perhaps using p to change x
*p = 2;
// DONE SPILL HERE, so reload register
... more code here not using p to change x.
}
else {
... lots of computations involving x.
}
An aggressive optimizer of this code might allocate a stack position for x, but load it into a register at the top of the code, maintaining it there except for the region marked as a SPILL. This region would be surrounded by a store of the register to memory and a matching register load.
C: Address on register or memory?
How does the address in a pointer look when it points on a register?
Pointers are a concept of memory, registers do not have addresses. Every processor has a limited, fixed amount of registers (8 - 16 probably).
As others have mentioned, the register
is not really useful anymore and even sometimes ignored by compilers.
To understand what registers really are, consider this example:
int a = k / 53; // k is an int defined somewhere else...
int b = a * 9;
// a is not used after the above line
Now, we have not declared a
with register
but any reasonable compiler will still keep a in a register.
The reason for this is that to perform any operation the operands have to be in certain registers. The the result of the operation will then e.g. be stored in the register of the first operand.
In order to compute a
from the above example, the compiler will write code to load k
(which presumably is in memory) into a certain register (let's call it register A) and 53 into another. After the computation is done, register A will contain the result of the operation. Since we are going to multiple that result by nine in the next line anyway, we can just keep it were it is, load 9 into the other register and multiply. Storing the value into memory and then loading it back into a register would just waste a lot of time.
Note that declaring a
with volatile
would prevent optimizations like this and force the compiler to actually store and load a
. (Although volatile
does not make any sense with this example here at all, and is hardly ever useful if you do not, for instance, interface special kind of hardware.)
Address of register variable when it is taken as auto variable
No. You can't. The standard is quite clear on this what operators are allowed to be applied on a register
storaged-classed variable regardless of whether an actual register is used or not:
C11, 6.7.1 Storage-class specifiers, p6
A declaration of an identifier for an object with storage-class
specifier register suggests that access to the object be as fast as
possible. The extent to which such suggestions are effective is
implementation-defined. 121121) The implementation may treat any register declaration simply as
an auto declaration. However, whether or not addressable storage is
actually used, the address of any part of an object declared with
storage-class specifier register cannot be computed, either explicitly
(by use of the unary & operator as discussed in 6.5.3.2) or implicitly
(by converting an array name to a pointer as discussed in 6.3.2.1).
Thus, the only operators that can be applied to an array declared with
storage-class specifier register are sizeof and _Alignof.
(emphasis mine)
Address of register variable when it is taken as auto variable
No. You can't. The standard is quite clear on this what operators are allowed to be applied on a register
storaged-classed variable regardless of whether an actual register is used or not:
C11, 6.7.1 Storage-class specifiers, p6
A declaration of an identifier for an object with storage-class
specifier register suggests that access to the object be as fast as
possible. The extent to which such suggestions are effective is
implementation-defined. 121121) The implementation may treat any register declaration simply as
an auto declaration. However, whether or not addressable storage is
actually used, the address of any part of an object declared with
storage-class specifier register cannot be computed, either explicitly
(by use of the unary & operator as discussed in 6.5.3.2) or implicitly
(by converting an array name to a pointer as discussed in 6.3.2.1).
Thus, the only operators that can be applied to an array declared with
storage-class specifier register are sizeof and _Alignof.
(emphasis mine)
Register Variable Address
The keyword register
is only a hint to the compiler. In fact, most compilers today ignore it as they contain advanced code to pick the best register variable candidates anyway.
Whenever you take the address of a variable, it is typically placed on the stack, despite the fact that you have used the register
keyword.
Why address-of operator ('&') can be used with objects that are declared with the register storage class specifier in C++?
The restriction on taking the address was deliberately removed in C++ - there was no benefit to it, and it made the language more complicated. (E.g. what would happen if you bound a reference to a register
variable?)
The register
keyword hasn't been much use for many years - compilers are very good at figuring out what to put in registers by themselves. Indeed in C++ the keyword is currently deprecated and will eventually be removed.
register keyword in C?
It's a hint to the compiler that the variable will be heavily used and that you recommend it be kept in a processor register if possible.
Most modern compilers do that automatically, and are better at picking them than us humans.
Related Topics
The Behaviour of Floating Point Division by Zero
Simple Glob in C++ on Unix System
Override a Member Function with Different Return Type
Template Specialization and Enable_If Problems
Overloaded Functions Are Hidden in Derived Class
How to Obtain C++ Type Names in a Constexpr Way
Create an Application Without a Window
How to Test If Preprocessor Symbol Is #Define'D But Has No Value
How to Add and Subtract 128 Bit Integers in C or C++ If My Compiler Does Not Support Them
Faq: Why Does Dynamic_Cast Only Work If a Class Has at Least 1 Virtual Method
How to Create the Cartesian Product of a Type List
Declare a Reference and Initialize Later
How to Handle Arbitrarily Large Integers
Keyboard Input & the Win32 Message Loop
Do You (Really) Write Exception Safe Code
Printing Values of All Fields in a C++ Structure
What Are the Use Cases for Having a Function Return by Const Value for Non-Builtin Type