Why does neither gcc or clang generate an error when I try to compile code containing the following two lines?
int palindrome(char s[]){
char s2[strlen(s)];
I thought in such an instance you would have to dynamically allocate memory to s2.
GCC has an extension for this behavior, and it's also standard in C99, known as variable length arrays.
http://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html
Clang supports it due to GCC C and C99: http://clang.llvm.org/compatibility.html#vla
Section 6.7.5.2 Array declarators:
If the size is not present, the array type is an incomplete type. If
the size is * instead of
being an expression, the array type is a variable length array type
of unspecified size,
which can only be used in declarations with function prototype
scope) such arrays are
nonetheless complete types. If the size is an integer constant expression
and the element
type has a known constant size, the array type is not a variable
length array type;
otherwise, the array type is a variable length array type.
And an example from 6.5.3.4:
#include <stddef.h>
size_t fsize3(int n)
{
char b[n+3]; // variable length array
return sizeof b; // execution time sizeof
}
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf (not the standard, but a draft, and free. :)
Related
I'm dynamically calculating the size of an array. Something like:
void foo(size_t limit)
{
char buffer[limit * 14 + 1];
}
But just GCC compiler says:
error: ISO C90 forbids variable length array ‘buffer’
searching on SO I found this answer:
C99 §6.7.5.2:
If the size is an expression that is not an integer constant
expression... ...each time it is evaluated it shall have a value
greater than zero.
So, I did the re-declaration of size limit type variable to:
void foo(const size_t limit)
But it continues to give warning for me. Is this a GCC bug?
const-qualifying a variable doesn't make it a compile-time constant (see C99 6.6 §6 for the defintion of an integer constant expression), and before the introduction of variable-length arrays with C99, array sizes needed to be compile-time constants.
It's rather obvious that const-qualify a variable doesn't make it a compile-time constant, in particular in case of function parameters which won't be initialized until the function is called.
I see the following solutions to your problem:
compile your code as C99 via -std=c99 or -std=gnu99
allocate your buffer via malloc()
use alloca() if available, which is the closest you can come to variable-length arrays with C90
choose a maximum buffer size which is always used and fail if the given limit argument overflows
As a side note, even though C99 allows variable-length arrays, it's still illegal to use the value of an integer variable with static storage duration as size for an array with static storage duration, regardless of const-qualification: While there's nothing which prevents this in principle if the integer variable is initialized in the same translation unit, you'd have to special-case variables with visible defintion from those whose definition resides in a different translation unit and would either have to disallow tentative defintions or require multiple compilation passes as the initialization value of a tentatively defined variable isn't known until the whole translation unit has been parsed.
const does not introduce a constant in C but a read-only variable.
#define SIZE 16
char bla[SIZE]; // not a variable length array, SIZE is a constant
but
const int size = 16;
char bla[size]; // C99 variable length array, size is a constant
C90 doesn't allow variable length arrays. However, you can use the c99-gcc compiler to make this work.
You are compiling with c90-gcc but looking at C99 specifications.
No it is not a bug. You can't use a VLA in C90. When you declared
const size_t limit
that is not a constant expression. A constant expression would be something like a literal value 666.
Note that C differs significantly from C++ in this regard. Even a constant like this
const int i = 666;
is not a constant expression in C. This is the primary reason why constant values are typically declared with #define in C.
As written in your question, this is from C99, not C90, you need to compile it against C99 to be able to use variable length arrays.
A const qualified variable is not an integer constant expression in the sense of the standard. This has to be a literal constant, an enumeration constant, sizeof or some expression composed with these.
Switch to C99 if you may. The gcc option is -std=c99 (or gnu99 if you want gnu extension.)
I am a bit confused about array declaration in C. I know that it's possible to do this:
int a[20]; // Reserved space for 20 int array
int b[] = {32, 431, 10, 42}; // Length in square brackets is auto-calculated
int *c = calloc(15, sizeof(int)); // Created a pointer to the dynamic int array
But is it possible to do this?:
int my_array[sizeof(int) * 5];
Is it a valid code, or an array length should be a constant expression (in ANSI C)?
This declaration
int my_array[sizeof(int) * 5];
does not declare a variable length array because the expression sizeof(int) * 5 is a constant integer expression. So even your compiler does not support variable length arrays you may use such a declaration.
From the C Standard (6.6 Constant expressions)
6 An integer constant expression117) shall have integer type and shall
only have operands that are integer constants, enumeration constants,
character constants, sizeof expressions whose results are integer
constants, and floating constants that are the immediate operands of
casts. Cast operators in an integer constant expression shall only
convert arithmetic types to integer types, except as part of an
operand to the sizeof operator.
and (6.7.6.2 Array declarators)
4 If the size is not present, the array type is an incomplete type. If
the size is * instead of being an expression, the array type is a
variable length array type of unspecified size, which can only be used
in declarations or type names with function prototype scope; such
arrays are nonetheless complete types. If the size is an integer
constant expression and the element type has a known constant size,
the array type is not a variable length array type; otherwise, the
array type is a variable length array type. (Variable length arrays
are a conditional feature that implementations need not support; see
6.10.8.3.)
A declaration of a variable length array can look like
const int n = 5;
int my_array[sizeof(int) * n];
The support of variable length arrays is optional in C11 and higher.
(This answer answers the question in the title, “Can array length in declaration be non-constant?” The example given in the body, int my_array[sizeof(int) * 5]; does not have a non-constant length.)
Variable length arrays are optional in the current C standard, 2018, meaning a C implementation may choose to support them or not. They were mandatory in the 1999 C standard and made optional in the 2011 standard.
Variable length arrays can be declared only inside functions or there parameters, not at file scope, and they cannot have static or thread storage duration.
sizeof(int) * 5 used in the example statement in your question: int my_array[sizeof(int) * 5];, is a constant expression, so although it does not serve as a good illustration of your primary question, it is legal syntax for C array declaration.
With the exception of C99, variable length arrays are optional in most recent C compiler implementations. (In C99 inclusion of VLA is mandated.)
So, if your compiler supports VLA, the following are an examples:
char string[100] = {0};
scanf("%99s", string);
int VLAarray1[strlen(string)+1];//per question in comments about functions to size array.
memset(VLA1array, 0, sizeof(VLAarray1));//see Note below for initialization
int arrayLen = 0;
scanf("%d", &arrayLen);
int VLAarray2[arrayLen];
memset(VLAarray2, 0, sizeof(VLAarray2));//see Note below for initialization
int nonVLAarray[100] = {0};//initialization during declaration of nonVLA
Note: that VLAs cannot be initialized in any form during its declaration. As with all variables though it is a good idea that it be initialized in subsequent statements by explicitly assigning values to its entire region of memory.
Passing VLAs as function arguments is not included within the scope of your question, but should it be of interest, there is a good discussion on that topic here.
I'm seeing some code like this:
int foo()
{
int sz = call_other_func();
char array[sz];
/* whatever */
}
I'm baffled at how this would work and even compile with gcc. The size of the array is supposed to be static and determined at compile time, no?
This type of arrays are called variable length arrays (you would also like to raed: Arrays of Variable Length - GCC) and are allowed in C99 only. By using VLAs, the size of the array can be determine at runtime.
"In programming, a variable-length array (or VLA) is an array data structure of automatic storage duration whose length is determined at run time (instead of at compile time)." (Wikipedia)
They're supported in C99 (and subsequently in C11).
Read more about how it works: The New C: Why Variable-length Arrays?
This is valid C99 feature called variable length arrays(VLA), if you compile with gcc -std=c90 -pedantic you will receive the following warning:
warning: ISO C90 forbids variable length array ‘array’ [-Wvla]
using -std=c99 -pedantic will not produce a warning, although both gcc and clang support VLA outside of C99 mode and also in C++ which does not allow VLA as an extension.
We can see from the C99 draft standard section 6.7.5.2 Array declarators paragraph 4 says (emphasis mine):
If the size is not present, the array type is an incomplete type. If the size is * instead of being an expression, the array type is a variable length array type of unspecified size, which can only be used in declarations with function prototype scope;124) such arrays are nonetheless complete types. If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.
Note that Visual Studio does not support VLA even though they now support C99
I'm programming in C99 and use variable length arrays in one portion of my code. I know in C89 zero-length arrays are not allowed, but I'm unsure of C99 and variable length arrays.
In short, is the following well defined behavior?
int main()
{
int i = 0;
char array[i];
return 0;
}
No, zero-length arrays are explicitly prohibited by C language, even if they are created as VLA through a run-time size value (as in your code sample).
6.7.5.2 Array declarators
...
5 If the size is an expression that is not an integer constant
expression: if it occurs in a declaration at function prototype scope,
it is treated as if it were replaced by *; otherwise, each time it is
evaluated it shall have a value greater than zero.
Zero-length arrays are not allowed in C. Statically typed arrays must have a fixed, non-zero size that is a constant expression, and variable-length-arrays must have a size which evaluates non-zero; C11 6.7.6.2/5:
each time it [the size expression] is evaluated it shall have a value greater than zero
However, C99 and C11 have a notion of a flexible array member of a struct:
struct foo
{
int a;
int data[];
};
From C11, 6.7.21/18:
As a special case, the last element of a structure with more than one named member may
have an incomplete array type; this is called a flexible array member. In most situations,
the flexible array member is ignored. In particular, the size of the structure is as if the
flexible array member were omitted except that it may have more trailing padding than
the omission would imply. However, when a . (or ->) operator has a left operand that is
(a pointer to) a structure with a flexible array member and the right operand names that
member, it behaves as if that member were replaced with the longest array (with the same
element type) that would not make the structure larger than the object being accessed;
Zero-length arrays are not allowed in standard C(not even C99 or C11). But gcc does provide an extension to allow it. See http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
struct line {
int length;
char contents[0];
};
struct line *thisline = (struct line *)
malloc (sizeof (struct line) + this_length);
thisline->length = this_length;
I'm dynamically calculating the size of an array. Something like:
void foo(size_t limit)
{
char buffer[limit * 14 + 1];
}
But just GCC compiler says:
error: ISO C90 forbids variable length array ‘buffer’
searching on SO I found this answer:
C99 §6.7.5.2:
If the size is an expression that is not an integer constant
expression... ...each time it is evaluated it shall have a value
greater than zero.
So, I did the re-declaration of size limit type variable to:
void foo(const size_t limit)
But it continues to give warning for me. Is this a GCC bug?
const-qualifying a variable doesn't make it a compile-time constant (see C99 6.6 §6 for the defintion of an integer constant expression), and before the introduction of variable-length arrays with C99, array sizes needed to be compile-time constants.
It's rather obvious that const-qualify a variable doesn't make it a compile-time constant, in particular in case of function parameters which won't be initialized until the function is called.
I see the following solutions to your problem:
compile your code as C99 via -std=c99 or -std=gnu99
allocate your buffer via malloc()
use alloca() if available, which is the closest you can come to variable-length arrays with C90
choose a maximum buffer size which is always used and fail if the given limit argument overflows
As a side note, even though C99 allows variable-length arrays, it's still illegal to use the value of an integer variable with static storage duration as size for an array with static storage duration, regardless of const-qualification: While there's nothing which prevents this in principle if the integer variable is initialized in the same translation unit, you'd have to special-case variables with visible defintion from those whose definition resides in a different translation unit and would either have to disallow tentative defintions or require multiple compilation passes as the initialization value of a tentatively defined variable isn't known until the whole translation unit has been parsed.
const does not introduce a constant in C but a read-only variable.
#define SIZE 16
char bla[SIZE]; // not a variable length array, SIZE is a constant
but
const int size = 16;
char bla[size]; // C99 variable length array, size is a constant
C90 doesn't allow variable length arrays. However, you can use the c99-gcc compiler to make this work.
You are compiling with c90-gcc but looking at C99 specifications.
No it is not a bug. You can't use a VLA in C90. When you declared
const size_t limit
that is not a constant expression. A constant expression would be something like a literal value 666.
Note that C differs significantly from C++ in this regard. Even a constant like this
const int i = 666;
is not a constant expression in C. This is the primary reason why constant values are typically declared with #define in C.
As written in your question, this is from C99, not C90, you need to compile it against C99 to be able to use variable length arrays.
A const qualified variable is not an integer constant expression in the sense of the standard. This has to be a literal constant, an enumeration constant, sizeof or some expression composed with these.
Switch to C99 if you may. The gcc option is -std=c99 (or gnu99 if you want gnu extension.)