Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why address-of operator ('&') can be used with objects that are declared with the register storage class specifier in C++?

Tags:

In C programming language we are not allowed to use address-of operator(&) with variables which are declared with register storage class specifier.

It gives error: address of register variable ‘var_name’ requested

But if we make a c++ program and perform the same task (i.e use the & with register storage variable) it doesn't gives us any error.

eg.

#include <iostream> using namespace std; int main() {     register int a;     int * ptr;     a = 5;     ptr = &a;     cout << ptr << endl;     return 0; } 

Output :-

0x7ffcfed93624 

Well this must be an extra feature of C++, but the question is on the difference between register class storage in C and C++.

like image 739
Amit Upadhyay Avatar asked Dec 06 '15 14:12

Amit Upadhyay


People also ask

Why address operator is used in C?

Address operator is used to storing the address of the variable in C. This is denoted by an ampersand (&). This is also used for scanning the user input.

Why do we use address of operator in C Scanf?

Because it needs the address to place the value it reads. If you declare you variable as a pointer, the scanf will not need the & .

Which symbol is used as a address operator?

The ampersand symbol & is used in C++ as a reference declarator in addition to being the address operator.

What does address mean in C?

When a variable is created in C, a memory address is assigned to the variable. The memory address is the location of where the variable is stored on the computer. When we assign a value to the variable, it is stored in this memory address.


2 Answers

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.

like image 57
Alan Stokes Avatar answered Oct 07 '22 22:10

Alan Stokes


The register storage class originally hinted to the compiler that the variable so qualified was to be used so frequently that keeping its value in memory would be a performance drawback. The vast majority of CPU architectures (maybe not SPARC? Not even certain there's a counterexample) cannot perform any operation between two variables without first loading one or both from memory into its registers. Loading variables from memory into registers and writing them back to memory once operated upon takes many times more CPU cycles than the operations themselves. Thus, if a variable is used frequently, one can achieve a performance gain by setting aside a register for it and not bothering with memory at all.

Doing so, however, has a variety of requirements. Many are different for every CPU architecture:

  • All processors have a fixed number of registers, but each processor model has a different number. In the 80s you might have had 4 that could reasonably be used for a register variable.
  • Most processors do not support the use of every register for every instruction. In the 80s it was not uncommon to have only one register that you could use for addition and subtraction, and you probably couldn't use that same register as a pointer.
  • Calling conventions dictated differing sets of registers that could be expected to be overwritten by subroutines i.e. function calls.
  • The size of a register differs between processors, so there are cases where a register variable will not fit in a register.

Because C is intended to be independent of platform, these restrictions could not be enforced by the standard. In other words, while it may be impossible to compile a procedure with 20 register variables for a system that only had 4 machine registers, the C program itself should not be "wrong", as there is no logical reason a machine cannot have 20 registers. Thus, the register storage class was always just a hint that the compiler could ignore if the specific target platform would not support it.

The inability to reference a register is different. A register is specifically not kept updated in memory and not kept current if changes are made to memory; that's the whole point of the storage class. Since they are not intended to have a guaranteed representation in memory, they cannot logically have an address in memory that will be meaningful to external code that may obtain the pointer. Registers have no address to their own CPU, and they almost never have an address accessible to any coprocessor. Therefore, any attempt to obtain a reference to a register is always a mistake. The C standard could comfortably enforce this rule.

As computing evolved, however, some trends developed that weakened the purpose of the register storage class itself:

  • Processors came with greater numbers of registers. Today you probably have at least 16, and they can probably all be used interchangeably for most purposes.
  • Multi-core processors and distributed code execution has become very common; only one core has access to any one register and they never share without involving memory anyway.
  • Algorithms for allocating registers to variables became very effective.

Indeed, compilers are now so good at allocating variables to registers that they will usually do a better job at optimization than any human. They certainly know which ones you are using most frequently without you telling them. It would be more complicated for the compiler (i.e. not for the standard or for the programmer) to produce these optimizations if they were required to honor your manual register hints. It became increasingly common for compilers to categorically ignore them. By the time C++ existed, it was obsolete. It is included in the standard for backward compatibility, to keep C++ as close as possible to a proper superset of C. The requirements of a compiler to honor the hint and thus the requirements to enforce the conditions under which the hint could be honored were weakened accordingly. Today, the storage class itself is deprecated.

Therefore, even though it is still the case today (and will be until computers don't even have registers) that you cannot logically have a reference to a CPU register, the expectation that the register storage class will be honored is so long gone that it is unreasonable for the standard to require compilers to require you to be logical in your use of it.

like image 23
sqykly Avatar answered Oct 07 '22 22:10

sqykly