6

As we know that address of the variable declared with register storage class can't be taken. So i tried to create an array with register keyword and tried to access the element . but i noticed that there is no any error raised by compiler.

#include <stdio.h>
void main()
{
   register int x[]={3,4};
   printf("%d\n",x[0]); // compiled successfully
  // printf("%d",&x[0]);// compiler raises an error
}

as we all know that compiler converts the expression x[0] to *(x+0) where x represents the base address. But how is it possible to get the base address of the array since it is declaraed with register storage class?

Thanks in Advance..

Abhishek Jaiswal
  • 288
  • 2
  • 14
  • Does this answer your question? ["register" keyword in C?](https://stackoverflow.com/questions/578202/register-keyword-in-c) – TomServo Apr 12 '21 at 02:34
  • 1
    `register` is only a compiler hint or suggestion. It does not guarantee storage in a register. As to you other question, which there shouldn't be either as there is supposed to be one question per question: *read the standard* yourself and these will not be mysteries. – TomServo Apr 12 '21 at 02:34
  • From Wikipedia and I am sure in many other references - "In C ... the location of a variable declared with register cannot be accessed." – xagyg Apr 12 '21 at 02:42
  • 2
    Note the gcc flag `-Wpedantic` results in "warning: ISO C forbids subscripting 'register' array" – aschepler Apr 12 '21 at 02:54

1 Answers1

7

Under the C standard, you are allowed to declare an array with register storage class, but it's basically useless; any attempt to use that array to form a pointer, much less to dereference that pointer (to access an element of the array), causes undefined behavior. C17 (n2176) 6.3.2.1 (3):

Except when it is the operand of the sizeof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type “array of type” is converted to an expression with type “pointer to type” that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

In fact, as emphasized in footnote 123 to 6.7.1 (6), pretty much the only thing you can legally do to a register array is to take sizeof of it.

So your example has undefined behavior; it's completely up to the compiler to decide what to do with it. One reasonable choice, and what yours probably does, is to just ignore the register keyword and treat the array like any other array. This is sensible because modern compilers ignore the register keyword in practically every other situation anyway, and make their own decisions when to optimize a variable into a register or not. The one thing it's not allowed to ignore is an attempt to apply the & operator, because that's a constraint violation by 6.5.3.2 (1), and this explains why you get an error when you try to do that.

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82
  • Okay i suppose what you are telling , but what about this? #include int main() { register int x[]={3,4}; printf("%d\n",x); return 0; } why is this program too giving error, "if the modern compiler ignore the register keyword and treat the array like any other way" as told by you? – Abhishek Jaiswal Apr 13 '21 at 06:41
  • @AbhishekJaiswal: Well I did say "probably", so maybe I'm wrong. Different compilers are free to do different things with `register` arrays in different contexts, since as mentioned it's all UB for the standard. You haven't even said what compiler you are using so I'm just guessing about what it might do. If you want the precise story about what *your* compiler does, please identify it and tag your question accordingly. (And of course check its documentation first.) – Nate Eldredge Apr 13 '21 at 14:05
  • oops sorry for that , now i have tagged the compiler name with this post which is GCC. – Abhishek Jaiswal Apr 14 '21 at 17:23
  • 1
    @AbhishekJaiswal: As far as I can tell, GCC's handling of `register` arrays is undocumented. You would probably have to dig into the compiler source code to see what it does, and even then it might change without warning between versions or with different optimization flags, etc. It sounds like perhaps it treats it as if `x[0]` and `x[1]` are two separate `register int` variables, but I think it would be unwise (and also pointless) to rely on that in any way. – Nate Eldredge Apr 14 '21 at 20:26
  • 1
    @AbhishekJaiswal: Incidentally, clang accepts the example from your comment without errors or warnings (once the incorrect format specifier is fixed: `%d` -> `%p` and cast to `void *`), and prints out an address on the stack. https://godbolt.org/z/cj3Mq3hdx – Nate Eldredge Apr 14 '21 at 20:30