Is it legal as per the C++ standard to convert a pointer or reference to a fixed array (e.g. T(*)[N]
or T(&)[N]
) to a pointer or reference to a smaller fixed array of the same type and CV qualification (e.g. T(*)[M]
or T(&)[M]
)?
Basically, would this always be well-formed for all instantiations of T
(regardless of layout-type):
void consume(T(&array)[2]); void receive(T(&array)[6]) { consume(reinterpret_cast<T(&)[2]>(array)); }
I don't see any references to this being a valid conversion in:
expr.reinterpret.cast
,expr.static.cast
,conv.array
, or evenbasic.types
However, it appears that all major compilers accept this and generate proper code even when optimized when using T = std::string
(compiler explorer)(not that this proves much, if it is undefined behavior).
It's my understanding that this should be illegal as per the type-system, since an object of T[2]
was never truly created, which means a reference of T(&)[2]
would be invalid.
I'm tagging this question c++11 because this is the version I am most interested in the answer for, but I would be curious to know whether this answer is different in newer versions a well.
A fixed array is an array for which the size or length is determined when the array is created and/or allocated. A dynamic array is a random access, variable-size list data structure that allows elements to be added or removed. It is supplied with standard libraries in many modern programming languages.
Arrays a kind of data structure that can store a fixed-size sequential collection of elements of the same type.
The neat thing about declaring a pointer like this is that you will get a compile time error if you try to assign a pointer of an array of different size to p. It will also give you a compile time error if you try to assign the value of a simple char pointer to p.
Assuming you have some understanding of pointers in C, let us start: An array name is a constant pointer to the first element of the array. It is legal to use array names as constant pointers, and vice versa. Therefore, * (balance + 4) is a legitimate way of accessing the data at balance [4].
The neat thing about declaring a pointer like this is that you will get a compile time error if you try to assign a pointer of an array of different size to p. It will also give you a compile time error if you try to assign the value of a simple char pointer to p. I tried this with gcc and it seems to work with ANSI, C89 and C99.
Assuming you have some understanding of pointers in C, let us start: An array name is a constant pointer to the first element of the array. Therefore, in the declaration − double balance ; balance is a pointer to &balance, which is the address of the first element of the array balance.
There’s not much to say here except no, in any language version: the types are simply unrelated. C++20 does allow conversion from T (*)[N]
to T (*)[]
(and similarly for references), but that doesn’t mean you can treat two different N
s equivalently. The closest you’re going to get to a “reference” for this rule is [conv.array]/1 (“The result is a pointer to the first element of the array.”, which T[2]
does not exist in your example) and a note in [defns.undefined] (“Undefined behavior may be expected when this document omits any explicit definition of behavior”).
Part of the reason that compilers don’t “catch” you is that such reinterpret_cast
s are valid to return to the real type of an object after another reinterpret_cast
used to “sneak” it through an interface that expects a pointer or reference to a different type (but doesn’t use it as that type!). That means that the code as given is legitimate, but the obvious sort of definition for consume
and caller for receive
would together cause undefined behavior. (The other part is that optimizers often leave code alone that’s always undefined unless it can eliminate a branch.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With