Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

address of register variable in C and C++

I know the concept of register variable and it's use cases but there are few questions in my mind based on what I have tried.

  1. I cannot access the address of a register variable in C though I can do it C++! Why? Is there any issue in accessing the addressing of a register variable?

  2. Suppose if I declare a string variable in C++ as register, then where will that variable be stored? What is the point in declaring the storage class of non-numeric data types such as 'string' in C++ to be register??

UPDATE: I thought that C++ allows us to fetch the address of a register variable, as I was not getting any error in my program which is as follows:

#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;
}

What I have observed is, if I make the variable 'i' as register and don't try to print the address using '&i' then C++ accepts the recommendation and stores 'i' in register, this can be infered from running time of for loop which will always be around 4-12 ms if 'i' is in register. But if I try to print address of variable 'i' then though I don't get any error but C++ rejects the recommendation and this can be infered from the time of execution of loop which is always more than 25 if i is not register!!

So, basically I cannot fetch address of a variable with storage class as register in both C as well as C++!! WHY?

like image 816
kunal18 Avatar asked Jul 09 '13 23:07

kunal18


4 Answers

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 an auto declaration. [...]

  • In C++, register is a deprecated, meaningless keyword that has no effect (except perhaps serve as a compiler hint), and variables declared as register 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.

like image 122
Kerrek SB Avatar answered Sep 25 '22 01:09

Kerrek SB


First, let's take a look at the relevant standards. It's always possible that C and C++ have different meanings for this keyword.

C++ 2011 Section 7.1.1 Paragraphs 2 and 3:

The register specifier shall be applied only to names of variables declared in a block (6.3) or to function parameters (8.4). It specifies that the named variable has automatic storage duration (3.7.3). A variable declared without a storage-class-specifier at block scope or declared as a function parameter has automatic storage duration by default.

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 (see D.2). — end note ]

C 2011 Section 6.7.1 Paragraph 6 and Footnote 121:

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.)

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.

So, let's take away what we've learned here.

  • In C++, the register keyword has no meaning. It does function as a compiler hint, but it's suggested that most compilers will ignore that hint anyways.
  • In C, the register keyword retains a meaning. Here, we are not, for example, allowed to take the address of an object (see the quoted footnote). An implementation may ignore the register hint, and place the object in memory anyways, but the keyword does restrict what you can do with the object. These restrictions should enable a compiler to better optimize access to the object, but it's also possible (like it is suggested in the C++ case), that the compiler will be able to infer this anyways.

As to what you're seeing in practice:

  • We can see why you're getting the syntax error in C when you try to take the address of a register int, so let's move past that.
  • You claim to be seeing a performance difference in C++ depending on whether or not you use register. In this case, it would be good to show your test, because there may be problems in the test itself. If the full test is fine, then it certainly is possible that your compiler is using the hint to produce better code.
  • The code you've shown is certainly odd though. That's because a compiler under optimizations will likely just remove the entire for loop from the code. The for loop has no side-effects. It's likely (and preferred) that a compiler will return identical code (that is, no code) with for (int i=0; i<100; ++i){} and for (register int i=0; i<100; ++i) {}.
like image 24
Bill Lynch Avatar answered Sep 23 '22 01:09

Bill Lynch


Taking the address of a variable will FORCE the compiler to store it in a memory (unless it's an architecure where registers has an address - I think the TI 9900 series processors were implemented this way, but it's a vague memory from ca 1984). If you have told the compiler to use a register, that makes it incompatible. Although the C++ standard seems to suggest that the compiler isn't obliged to tell you so, and can in fact ignore the register keyword.

C++11 draft n3337, section 7.1.1, bullet 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 (see D.2). — end note ]

(Edit: Yes, the TMS 9900 does indeed have "registers in memory", so theoretically, you can have the address of a register in that architecture - but the architecture is much more that "registers live in memory (which has an address)" than "registers have addresses").

like image 37
Mats Petersson Avatar answered Sep 27 '22 01:09

Mats Petersson


The basic answer is that, on most architectures, general purpose registers do not have memory addresses. In general, a pointer is simply a (virtual) memory address of the memory location containing the object. This is done of efficiency.

It would be possible to extend the concept of a pointer to point to memory or register. However, doing so would decrease program speed as the code to dereference a pointer would need to check what type of location is being pointer to.

like image 22
DoxyLover Avatar answered Sep 24 '22 01:09

DoxyLover