Search code examples
cclangc89storage-class-specifierregister-keyword

Why register array names can be assigned to pointer variables without compiler error?


I have a question about register keyword in C.

I found that register array name(e.g. array) can be assigned to pointer variable while &array[0] cannot be.

Can you explain why array name can be assigned to pointer? Or, if someone already explained it, please let me know links so that I can take a look to get the answer. Thank you.

Here is what I tried:

I read cppreference which explains register keyword and it says:

register arrays are not convertible to pointers.

Also, I read C89 draft which says:

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 may not be computed, either explicitly (by use of the unary & operator as discussed in 3.3.3.2) or implicitly (by converting an array name to a pointer as discussed in 3.2.2.1). Thus the only operator that can be applied to an array declared with storage-class specifier register is sizeof.

This looks like I can't assign register array name to pointer to get its address.

Moreover, to find the answer, I searched here and found this question: Address of register variable. There are good answers, however, still I couldn't find the answer what I wanted.

Here is the code which I tested. I compiled this code through Clang with flag -std=c89:

register int array[10];
int* p;

p = array;     // Compiled without warning or error
p = &array[0]; // Compiled with error which I expected

I expected both p = array; and p = &array[0]; caused compiled error, but only p = &array[0]; made a compile error.


Solution

  • This is a bug in the Clang compiler. GCC shows an error on both lines.

    In discussing the automatic conversion of “array of type” to “pointer to type”, C 2018 6.3.2.1 says:

    … If the array object has register storage class, the behavior is undefined.

    Further, C 2018 footnote 124 says:

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

    Obviously, p = array; converts array to a pointer, as discussed in 6.3.2.1, but this footnote (which is non-normative but tells us the intent in this case quite explicitly) says the value for that pointer cannot be computed.

    Since the behavior is not defined by the C standard, a C implementation could define it as an extension. However, the inconsistent behavior between array and &array[0] suggests this is not a deliberate extension by Clang but is a mistake.