Home > Software engineering >  Array declared with negative buffer works if done with a variable
Array declared with negative buffer works if done with a variable

Time:11-30

I'm new to C programming and I'm struggling really hard to understand why this works

#include <stdio.h>


int main() {
    int l = -5;
    char arr[l];

    printf("content: %s; sizeof: %d\n", arr, sizeof(arr));
}

with output:

content: ; sizeof: -5

and this doesn't:

#include <stdio.h>


int main() {
    char arr[-5];

    printf("content: %s; sizeof: %d\n", arr, sizeof(arr));
}

with output:

name.c:6:10: error: size of array ‘arr’ is negative
    6 |     char arr[-5];
      |          ^~~

I was expecting an error also from the first example, but I really don't know what's happening here.

CodePudding user response:

Neither version of the program conforms to the C language specification (even after the format specifiers are corrected to properly match the size_t argument). But the two cases are semantically different, and they violate different provisions of the language specification.

Taking this one first:

    char arr[-5];

The expression -5 is an integer constant expression, so this is a declaration of an ordinary array (not a variable-length array). It is subject to paragraph 6.7.6.2/1 of the C17 language spec, which says, in part:

In addition to optional type qualifiers and the keyword static, the [ and ] may delimit an expression or *. If they delimit an expression (which specifies the size of an array), the expression shall have an integer type. If the expression is a constant expression, it shall have a value greater than zero.

(Emphasis added.)

That is part of a language constraint, which means that the compiler is obligated to emit a diagnostic message when it observes a violation. In principle, implementations are not required to reject code containing constraint violations, but if they accept such codes then the language does not define the results.

On the other hand, consider

    int l = -5;
    char arr[l];

Because l is not a constant expression (and would not be even if l were declared const), the provision discussed above does not apply, and, separately, arr is a variable-length array. This is subject to paragraph 6.7.6.2/5 of the spec, the relevant part requiring of the size expression that:

each time it is evaluated it shall have a value greater than zero

The program violates that provision, but it is a semantic rule, not a language constraint, so the compiler is not obligated to diagnose it, much less to reject the code. In the general case, the compiler cannot recognize or diagnose violations of this particular rule, though in principle, it could do so in this particular case. If it accepts the code then the runtime behavior is undefined.

Why this program emits -5 when you compile and run it with your particular C implementation on your particular hardware is not established by C. It might be specified by your implementation, or it might not. Small variations in the program or different versions of your C implementation might produce different results.

Overall, this is yet another example of C refusing to hold your hand. New coders and those used to interpreted languages and virtual machines seem often to have the expectation that some component of the system will inform them when they have written bad code. Sometimes it does, but other times it just does something with that bad code that might or might not resemble what the programmer had in mind. Effective programming in C requires attention to detail.

  • Related