简体   繁体   中英

C: Address on register or memory?

I am a bit confused by the key word "register" in C. It seems to tell the compiler that it should be stored in a register wich means that some of my variables are stored in Registers and some in memory? If so, is there a way to find out whether my value is stored in a register or in Memory?

For example:

int *x =  (int*) 0x1234;

X does not seem to point on a register now, because such addresses are for memory. But I have tried several times to find a different looking address (also using "register" key word). Even on the internet nobody seems to care.

So my main quesition: How does the address in a pointer look when it points on a register?

EDIT: I cant find an answer to my main question at the end of my question in the other question. My question is NOT about the key word "register", I just mentioned it.

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

The storage class specifier register was created on first release of C language to instruct compiler to use one of the processors registers to hold the variable having the scope to allow for faster access. At that time code writing required much attention from the programmer because the compilers were not so smart to detect errors or correct them leading to buggy code.

Anyway while growing-up the C standard got some tricks that made difficult to understand some details.

The storage class specifier register is one of those. So let's start looking at specs before to comment them.

From ISO/IEC 9899:2011 , C11 standard:

§6.7.1 Storage-class specifiers

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. (See note 119)

And the note 119:

NOTE

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 operator that can be applied to an array declared with storage-class specifier register is sizeof.

This means that the storage specifier register is a suggestion to the compiler to use processor registers or any other means to make the variable access as fast as possible, but the compiler can take a different decision. It can treat the declared variable as a standard auto variable.

In the last case it could be technically possible to obtain the storage address, but this is explicitly prohibited by the standard as explained in the note, but also enforced in the constraints of §6.5.3.2 Address and indirection operators :

The operand of the unary & operator shall be either a function designator, the result of a [] or unary * operator, or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier .

Of course some uncompliant compilers may let you apply the operator.

Now going back to your very question:

  1. int *x = (int*) 0x1234; X does not seem to point on a register now, because such addresses are for memory. But I have tried several times to find a different looking address (also using "register" key word). Even on the internet nobody seems to care.

Your example is wrong , you are declaring a pointer to an int and assigning an arbitrary address to it. This has nothing to do the register storage specifier.

Declare register int *x = (int*) 0x1234; and then try to apply the & operator to x as in int **pp = &x; (note that we are declaring a pointer to a pointer to int that is what we get taking the address of a pointer to int ).

You'll get an error on compliant compilers.

  1. So my main quesition: How does the address in a pointer look when it points on a register?

The answer is simple: it doesn't resemble anything because it can't exist in standard C .

In modern compilers, an object you declare in C does not necessarily have a single location in which it exists. To optimize your program, the compiler may keep it in a register at some times, on the stack at others, or in a particular memory location at others. Normally, you do not need to know which.

When you take the address of the object and work with pointers, the compiler makes your program work as if the object did have a fixed address. Often this is done by putting the object in an assigned memory location, at least for the duration of time that you are using its address, but the compiler is allowed to achieve the end results of your program by other means.

If you declare an object with register , you are not supposed to, by the C standard, take its address. However, some compilers may permit this.

In most architectures you cannot point to a CPU register as they are not memory mapped. (8051 is one architecture I can think of where the core registers are memory mapped).

If you are referring to peripheral registers on the other hand; these are memory mapped and have addresses in the address space, and the declaration would be just as you have it - except you do need the volatile type modifier.

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

The register keyword has nothing to do with memory mapped peripheral registers .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM