All C compilers are actually required to allow you to pass a size like that. It doesn't have any effect whatsoever, though. Any number you put between those  is really just decoration. These 4 function declarations are totally equivalent:
Yes. But not every array in C++ uses the STL class, and I was reacting to Simon's comment about the '' index operator.
It would be hopelessly confusing if the index operator of the array class was checked, but the general (C compatible) index operator was not. If the general operator were checked, undoubtedly some code would break, and even though STL arrays are heap allocated with some overrun slop, I suspect that checking the operator there also would break some existing code. [Not that breaking crappy code is a bad thing ... 8-) ]
Specifying the size here is just a comment. And it is a dangerous comment, because it /looks/ like it might be something that the compiler will check, or that lets you use "sizeof" in the manner you describe - but it will not. In all the cases above, "x" is a pointer to char - /not/ an array.
Section 126.96.36.199 "Function declarators (including prototypes)" of the C standards has paragraph 7:
A declaration of a parameter as ??array of type?? shall be adjusted to ??qualified pointer to type??, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.
Using an array as a parameter type has /exactly/ the same effect as using a pointer. Applying "sizeof" to it returns the size of a pointer.
C++ has the same thing (but without the option is using "static"). The wording in C++14 section 8.3.5 paragraph 5 is different but gives the same results.
As a programmer, you absolutely should /not/ have to check that the compiler follows the fundamental rules of the language you are using. A compiler - C or C++ - which gives the "sizeof" a C array parameter as the sizeof the array rather than the size of the pointer, is /broken/. This is not an option, or a feature, or something that some compilers do
- it is how C and C++ arrays work. And it is part of the reason for the introduction of std::array in C++.
Changing the behavior of the '' operator in native C++ code is a completely different class of change than changing the behavior of the '' operator in a library. The first requires a change to the underlying language definition, while the second is only a change to the library code.
Control systems, embedded software and circuit design
Type safety is primarily a compile-time feature. The aim of type safety is to stop you trying to use the wrong "type" of "thing" (objects, classes, types, whatever) in the wrong place. And by restricting the operations you can do on your "things", you spot more mistakes at compile-time. A vital point is that type safety checks are free with respect to run-time costs. And your aim is to stop certain classes of error being /possible/.
Checking the bounds of array accesses is primarily a run-time feature. There are run-time safety checks you can make - they are not type safety checks. They involve some run-time overhead, and you need run-time methods of dealing with detected errors - your aim is to detect certain classes of error when they happen, and stop them leading to worse problems.
Sometimes there is a middle ground. The compiler may be able to check, at compile time, whether an array access is always safe, possibly safe, or always bad. It is certainly a good thing if the compiler can warn you on third case, and omit any run-time checks in the first case.
You can argue that a std::array type is a type with a fixed known size, and therefore should not allow any access beyond its bounds. But actually it is defined as a type that wraps a C array with no run-time overheads for normal use, without run-time checking of bounds. It gives you methods for accessing the data, but there is a pre-condition on the  operator that you are within the bounds of the array. This is a perfectly good way to define a type and its operations - type-safety does /not/ require run-time checking that pre-conditions to methods are met. That is the responsibility of the code using the type.
Of course one could make a type for which bounds checking was part of the  operator method specification. But even then, the check is not part of the type safety system because the index is not part of a type, and the check is not at compile-time. If you want that kind of type safety, use a std::tuple and get functions for access - /those/ accesses are type checked.
Fair enough, I suppose. C++ supports dynamic type safety too, such as the dynamic_cast operator. But static type safety is the main mechanism for type safety in C++.
std::array is defined to be a type with greater static type safety compared to standard C/C++ arrays - it knows its size, does not decay to a pointer, etc. It is not defined to have run-time bounds checking by default - but you have the option if you want (with the "at" method).
Type safety - dynamic or static - does not mean preventing any possible errors. It merely means making it hard to accidentally make errors from mixing up types - and it is a balance between safety, convenience (in writing the code) and efficiency (code size and speed at run-time). It is not an absolute term (at least, not in real-world programs in real-world programming languages). It would be fair to say that an array container that always checked its bounds is /safer/ than std::array, and is more "type safe". But it could never be completely type safe - not in C++, where you have reinterpret_cast, unions, void*, memcpy, and all sorts of other ways to cheat on type safety.