Variable-length arrays in C89? - c

I've read that C89 does not support variable-length arrays, but the following experiment seems to disprove that:
#include <stdio.h>
int main()
{
int x;
printf("Enter a number: ");
scanf("%d", &x);
int a[x];
a[0] = 1;
// ...
return 0;
}
When I compile as such (assuming filename is va_test.c):
gcc va_test.c -std=c89 -o va_test
It works...
What am I missing? :-)

GCC always supported variable length arrays AFAIK. Setting -std to C89 doesn't turn off GCC extensions ...
Edit: In fact if you check here:
http://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html#C-Dialect-Options
Under -std= you will find the following:
ISO C90 programs (certain GNU
extensions that conflict with ISO C90
are disabled). Same as -ansi for C
code.
Pay close attention to the word "certain".

C89 does not recognize // comments.
C89 does not allow definitions intermixed with code.
You need to fflush(stdout) after the printf to be sure of seing the prompt before the scanf.
main "looks better" as int main(void)
Try gcc -std=c89 -pedantic ... instead

You're missing that without -pedantic, gcc isn't (and doesn't claim to be) a standard-conforming C compiler. Instead, it compiles a GNU dialect of C, which includes various extensions.

Related

Apparently undocumented GCC behaviour with "constant" initializers in C

Consider the following C code:
#include <stdio.h>
int x = 5;
int y = x-x+10;
int z = x*0+5;
int main()
{
printf("%d\n", y);
printf("%d\n", z);
return 0;
}
The ANSI C90 standard states "All the expressions for an object that has static storage duration [...] shall be constant expressions" (6.5.7 constraint 3).
Clearly the initializers for y and z are not constant expressions. And indeed, trying to compile the above C code with clang main.c or clang -ansi main.c gives an error for this reason.
However, compiling with gcc main.c or even gcc main.c -ansi -pedantic -Wextra -Wall gives no errors at all, and runs, printing 10 and 5.
On the other hand, trying something like the following:
#include <stdio.h>
int x = 5;
int main()
{
int y[x-x+2];
printf("%lu\n", sizeof(y));
return 0;
}
gives a warning when compiled with gcc -ansi -pedantic ... or clang -ansi -pedantic ....
So gcc randomly performs the mathematically correct cancellations in order to pretend that something is a constant expression, even when asked not to (-ansi). Why is this? Is this a bug?
By the way, my gcc version is 9.4.0 and my clang version is 10.0.0-4.
Without looking, there's one simple explanation: the code that checks whether the initializer is an acceptable constant expression operates on an internal representation after a pass that does arithmetic simplification, so it never "sees" your x-x or x*0.
This probably makes the implementation of the rule in GCC simpler: it just has to ask "is this node one that represents a constant?" rather than "is this tree one that I could evaluate as a constant later on?". It also facilitates the behavior that they probably want for the later standards (see below), and a special case for -ansi would probably add an undesirable amount of code complexity.
Is it a bug? Arguably. But it's one with such a small impact that it's not especially likely to get fixed. It works correctly for valid code, and it errors correctly on "really" invalid code that could actually cause a problem. It only deviates from the standard in a fairly harmless way, and only for C90 (since the C99 and later standards say "an implementation may accept other forms of constant expressions", which gives GCC latitude to allow an expression that mentions things not on the laundry list, as long as it has a constant value).

In C why the parameter passed to a void function is compiled while it has to throw an error

#include<stdio.h>
void fun(z)
{
printf("%d",z);
}
int main()
{
int a=5;
fun(a);
}
This is giving output as 5. Shouldn't it give an error - undeclared variable z ?
Is this a compiler optimization ?
This is not a compiler optimization, it is a compliance with an ancient C convention that allowed you to skip variable and parameter types when the desired type is int. This convention pre-dates the ANSI standard, and should be avoided even if your compiler is fine with such code.
You will get a warning if you tell the compiler that you want your code to comply with one of more modern standards, say, C99 or C11. The flag is compiler-dependent. If you are using gcc, add
-std=c99
flag to see the warning.

Can i use a variable to declare the size of an array? C

Can i do something like this? I think you can because it works, but i am not sure if it is 100% correct.
printf("Array size: ");
scanf("%d", &n);
int array[n]; // I know this only works with C99
Variable length arrays are strictly a C99 feature. Compilers like GCC and Clang allow them to be used in C90 (ansi and C89) mode as well as C++. For example, see the GCC docs and the Clang docs. Both compilers have caveats or extensions that may offer or restrict certain features when using VLAs. One example of a GCC specific extension is the following code which does not compile in Clang:
void tester (int len; char data[len][len], int len)
{
}
In both compilers, -pedantic will warn about usage in standard modes where VLAs are non-standard.
In C11, support for variable length arrays are optional. The C11 standard specifies a "feature test" macro that states whether or not the implementation supports them.
§6.7.6.2 [...] (Variable length arrays are a conditional feature that
implementations need not support; see 6.10.8.3.)
§6.10.8.3 _ _STDC_NO_VLA_ _ The integer constant 1, intended to
indicate that the implementation does not support variable length
arrays or variably modified types.
Yes it works in C-99 and other language like C++
printf("Array size: ");
scanf("%d", &n);
int array[n];

Can't comment // on codeblocks

I'm using codeblocks to learn C programming.
When I use /* */ the program works, but when I use // the program returns this error.
expected identifier or ‘(’ before ‘/’ token|
here's the main.c
#include <stdio.h>
#include <stdlib.h>
//Ex1
int i;
float p;
char *n;
int main(void)
{
i = 22;
p = 70.0;
n = "Samuel";
printf("%s %d %.2f", n, i, p);
return 0;
}
From wiki:
C++ style line comments start with // and extend to the end of the line. This style of comment originated in BCPL and became valid C syntax in C99; it is not available in the original K&R C nor in ANSI C:
If you use gcc compiler, then add -std=c99 compiler argument.
It will enables C99 features, like // comments.
If you have -ansi option, then remove it.
Four major versions of the C language exist:
ISO 9899:2011. The current standard, known as C11. Allows //.
ISO 9899:1999. An obsolete standard, known as C99. Allows //.
ISO 9899:1990. An obsolete standard, known as C90, or sometimes C89. Does not allow //.
Pre-standardization. Known as "K&R C". Does not allow //.
Make sure to use a modern compiler with support for the relevant standard. Today, you should demand that a C compiler at least conforms with C99.

Why does this compile with the Dev-C++ compiler and not Visual Studio's one?

Why does the following code compile with the Dev-C++ compiler and
not with Visual Studio?
Any idea? Here is the code:
#include<stdio.h>
main(){
int n,i;
scanf("%d",&n);
int arr[n];
for(i= 0 ; i <n ; i++)
{
//Do something with the array
}
fflush(stdin);
getchar();
}
Here are the errors:
Errors http://img688.imageshack.us/img688/6618/26863513.jpg
This:
int arr[n];
is invalid because n is not a constant expression. You need to allocate variable sized arrays on the heap using malloc (and then free them when you are done with free).
If you are trying to compile this with a .cpp extension, main must have a return type of int. If you are trying to compile this with a .c extension, then you need to use c-style local variable declaration and declare all of your local variables at the top of the function.
Visual C++ doesn't do stack allocations with that syntax (though I wish it did). You can do stack allocations explicitly with:
int *arr = (int *)_alloca(n*sizeof(*arr));
and no need to free it since it's automatically freed when the scope ends.
This isn’t valid C++ – the Visual C++ compiler does not contain an up-to-date C compiler (rather a C subset of C++) and in particular it doesn’t implement C99 or anything newer. Your code uses features that the Visual C++ compiler doesn’t know (int arr[n]).
To simplify the answers you have gotten:
Your code is C99 and Visual C++ only supports C89. Do yourself a favour and get a better compiler for Windows. The Intel compiler has much better support for C99 than the Microsoft compiler (which has none).
Your program is not a Standard compliant program.
Any standard compliant compiler is required to issue a diagnostic when attempting to compile it.
If Dev-C++ compiled it without a warning, the compiler was invoked in a non compliance mode.
Other than the required diagnostic, a compliant compiler can attempt to compile anyway or just plainly abort compilation.
main()
In C89 this is valid and requires no diagnostic, In C99 this is invalid and requires a diagnostic (valid C99 definitions are int main(void) or int main(int argc, char **argv) or equivalent) ... so if you are using a compliant compiler it is a C89 compiler.
scanf("%d",&n);
int arr[n];
Oops, this is invalid in C89. In C89 you cannot have code intermixed with declarations. A C89 compiler must issue a diagnostic when it sees the declaration of the array.
So ... you are using your compiler in a non-conforming way. There's no way to tell why it compiles or fails to compile.

Resources