1) Why does this even compile? I thought only constexpr may be used for array size
The asker is correct that Variable Length Arrays (VLAs) are not Standard C++. The g++ compiler includes support for VLAs by extension. How can this be? A compiler developer can add pretty much anything it wants so long as the behaviour required by the Standard is met. It is up to the developer to document the behaviour.
2) Suppose the above is valid, it still does not explain why it works even when sz = 8 which is clearly less than the size of the character string
Normally g++ emits an error if an array is initialized with values that exceed the size of the array. I have to confirm with documentation to see whether the C++ Standard requires an error in this case. It seems like a good place for an error, but I can't remember if an error is required.
In this case it appears that the VLA extension has a side effect that eliminates the error g++ normally spits out for trying to overfill an array. This makes a lot of sense since the compiler doesn't know the size of the array, in the general case, at compile time and cannot perform the test. No test, no error.
None of this is covered by the C++ Standard because VLA is not supported.
A quick look through the C standard, which does permit VLAs, didn't turn up any guidance for this case. C the rules for initializing VLAs are pretty simple: You can't. The compiler doesn't know how big the array will be at compile time, so it can't initialize. There may be an exception for string literals, but I haven't found one.
I also have not found a good description of the behaviour in GCC documentation.
clang produces the error I expect based on my read of the C standard: error: variable-sized object may not be initialized
Addendum: Probably should have checked Stack Overflow first and saved myself a lot of time: Initializing variable length array .
3) Why are we getting that weird '@' and '?'. I tried different combination of strings, for example, only number characters ("123456789") and it did not appear.
What appears to be happening, and since none of this is standard I have no quotes to back it up, is the string literal is copied into the VLA up to the size of the VLA. The portions of the literal past the end of the VLA are silently discarded. This includes the null terminator, and the behaviour is undefined when printing an unterminated char
array.
Solution:
Stick to Standardized behaviour where possible. The major compilers have options to warn you of non-Standard code. Use -pedantic
with compilers using the gcc options and /permissive-
with recent versions of Visual Studio. When forced to step outside the Standard, consult the compiler documentation or the implementers themselves for the sticky-or-undocumented bits.
If you don't get good answers, try to find another path.