2

I've encountered a weird issue when trying to declare array on the stack in C. I always thought (until now at least) that it was impossible to declare array on the stack without a constant expression. E.g trying to compile the following code on VS2015 on Windows:

int main()
{
    int i = 3;
    int test[i];

    return 0;
}

Yields an "Expression must have a constant value" error, which is what I expected, but compiling the same code with gcc and clang on a Linux machine works. At first I thought it's probably the compilers inferring stuffs, so I tried the following:

int main()
{
    int i = 3;
    int j = i*i;
    int test[j];

    return 0;
}

And again VS2015 complained with the same error but gcc and clang compiled it just fine! I immediately thought, OK so maybe those compilers are inferring that as well, it is after all, just "constant" expressions. So I tried the following:

int main()
{
    int i = getchar();
    int test[i];

    return 0;
}

Surely the compiler can't infer this, the value of i when used to declare test can only be known at runtime, but to my surprise, again, VS2015 complained, but gcc and clang compiled it... Even adding the following:

int main()
{
    int i = getchar();
    int test[i];

    printf("%d\n", sizeof(test) / sizeof(int));

    return 0;
}

And entering the character x which it's value is 120 in the ASCII table, outputting 120.

What's going on?

M.M
  • 138,810
  • 21
  • 208
  • 365
UnTraDe
  • 3,747
  • 10
  • 36
  • 60
  • This is technically possible because the array is on the top of stack. But I don't plan to use this feature. – i486 Feb 23 '16 at 10:43
  • 1
    [Variable-length array](https://en.m.wikipedia.org/wiki/Variable-length_array) – Spikatrix Feb 23 '16 at 10:45
  • 1
    `int test[i];` does not initialise the array - `int test[i] = {};` would. I believe you mean "declare". – molbdnilo Feb 23 '16 at 10:56
  • @molbdnilo Thanks, I'll edit – UnTraDe Feb 23 '16 at 10:56
  • Visual Studio is a C++ compiler. It doesn't follow any C standard well, it is not a conforming implementation. It mainly tries to follows the 1989 version of C. Visual Studio 2015 also makes some attempts to follow parts of the 1999 version. Where other, modern compilers follow the 2011 version of C. You should use a modern compiler instead of Visual Studio, if possible. – Lundin Feb 23 '16 at 12:25
  • @Lundin Do you have any source for that? Because from the compiler options you can compile "C only" code. And personally I like clang way more, but for Windows I'm not familiar with a better option. Also, I really like Visual Studio as an IDE – UnTraDe Feb 23 '16 at 12:55
  • 1
    @UnTraDe Use common sense. All your 4 examples are perfectly fine C, and has been so for the past 17 years. Yet Visual Studio incorrectly gives you errors and warnings. As for sources, see [this](https://msdn.microsoft.com/en-us/library/hh409293.aspx#BK_CRT). Not until 2015 they upgraded to support the 1999 standard. And from what I hear, the support is far from complete. VS is simply not a good C compiler, period. – Lundin Feb 23 '16 at 13:35
  • @molbdnilo VLAs cannot have initializers – M.M Jan 22 '17 at 02:11

1 Answers1

5

You encountered VLAs (Variable-Length Arrays).
As opposed to "usual" arrays they take a value determined at runtime as the size specifier.

Since VS2015 primarily supports C89 and VLAs have been introduced in C99, they are not supported by Visual Studio and an error is issued.

Note that VLAs are a feature of C. C++ does not support them.

Community
  • 1
  • 1
cadaniluk
  • 15,027
  • 2
  • 39
  • 67
  • 1
    Correct. But note: this feature relegated to optional in C11. Summary here: https://en.wikipedia.org/wiki/C11_%28C_standard_revision%29. – david.pfx Feb 23 '16 at 10:53
  • @david.pfx: Compilers have never been required to support the feature in a particularly useful fashion. There is no context (even at top-level "main()", where a conforming implementation would be required to guarantee that a VLA allocation of any particular size (even a single element) would succeed, nor is there any limit on what a conforming implementation may do in case of failure. Put those together, and a conforming compiler would be allowed to treat any attempt to allocate a VLA as invoking Undefined Behavior. A quality compiler shouldn't behave in such a fashion, but... – supercat Jan 24 '17 at 22:57
  • ...it's better to allow compilers to refuse compilation of code they can't run usefully than to require that they accept the code but allow them to behave in arbitrary fashion if it's executed. – supercat Jan 24 '17 at 22:57
  • @supercat: Just so. Another case of "it sounded like a good idea at the time" but now serves to help some and confuse others. Best not to rely on... – david.pfx Jan 25 '17 at 03:52
  • @david.pfx: I wish the authors of the Standard would put more emphasis on constructs which are useful on some but not all implementations, and specify that implementations are not required to support such constructs, but must reject any they cannot support. IMHO, the Standard for implementations and programs should be written to define "Selectively-Conforming program" such that most tasks that can be done in C could be done with Selectively Conforming programs, but any conforming implementation given such a program would be required to process it without UB (noting that... – supercat Jan 25 '17 at 15:05
  • ...trapping in an implementation-defined manner whose default behavior will force abnormal termination would not be UB). As the Standard is written, the ability of an implementation to run more than one program without UB is a "quality of implementation" issue. I think it would be much more helpful to recognize a category of implementations which could offer a much stronger guarantee--not all programs would run, but those that couldn't would be guaranteed to fail only in certain predictable ways. – supercat Jan 25 '17 at 15:09