GCC Allows Arrays of Variable Length!!

This is very surprising. When I was learning C, I was convinced that array size must be determined at compile time, and I never wrote a line of code that violate this. Today, my friend (a C beginner) asked me to help him to debug his code. His code contains following lines:

[sourcecode lang=”c”]
…..
int T, R, C, i, j;
…..
char tile[R][C];
…..
[/sourcecode]

To my great surprise, this code compiles with no error. According to this post and this page, C99 allows array size to be a variable, which is supported by GCC. This feature may free programmer from many new, delete, malloc, free and memory leak in many cases.

C code that print its own source

Very interesting. The trick is that use s to print itself, thus s should not contain any character like “\n”, “\”” which will be displayed differently as its literal value. Thus, we use numbers to represent those special characters.
[sourcecode language=”cpp”]
#include <stdio.h>
int main(){const char *s="#include<stdio.h>%cint main(){const char *s=%c%s%c;printf(s,10,34,s,34);}";printf(s,10,34,s,34);}
[/sourcecode]

extern “C”

You may have seen following C++ code somewhere.

[sourcecode language=”cpp”]
extern "C"{
….
}
[/sourcecode]

Why do we need the extern “C”?

The answer is available in this post. The idea is, C++ compiler treat c++ differently from C. A function void f(int i) in C code is translated into _f in assembly, while the same function in C++ code will be translated into __Z1fi(the i at the end means first parameter is i, but I am not sure what does __Z1 seems represent return type). Compiler determin whether the code is C or C++ by looking at file extension only(.c for c file, .cpp for c++ file). C++ code is treated differently because C++ language support function overloading. That is to say, void f(int n) and void f(char c) are two different function because they have different parameter type. Compiler implement this by using different names for these two functions: including parameter type into function name. This method works fine, but when you want to call a C function in your C++ code, and the C function is already compilede as C code, then you have trouble.

[sourcecode language=”cpp”]
// sqr.c
int sqr(int n){
return n*n;
}
[/sourcecode]
[sourcecode language=”cpp”]
// main.c
#include<stdio.h>
int sqr(int n); //declaration
int main(){
printf("%d\n",sqr(10));
return 0;
}
[/sourcecode]
The code above works fine. However, if you rename “main.c” into “main.cpp”, then you have problem: compiler(actually linker) complains that “int sqrt(int) is not defined”. This is because, as a c++ function, “sqr” in “main.cpp” is translated into “__Z3sqri”, while as C code, “sqr” in “sqr.c” is translated into “_sqr”. Thus, linker cannot find the function “int sqrt(int)”. To solve this problem, we can use extern “C”{} to enclose sqr function declaration, so that the function name is translated into C style.
[sourcecode language=”cpp”]
// main.cpp
#include<stdio.h>
extern "C"{
int sqr(int n); //declaration
}
int main(){
printf("%d\n",sqr(10));
return 0;
}
[/sourcecode]

Please compile and link above code using g++ instead of gcc, or else you may get “undefined reference to `__gxx_personality_v0′” problem.

You may ask why functions declared in “stdio.h” works well for both C and C++ code? You can check out preprocessor’s output:

[sourcecode language=”cpp”]
//dummy c++ code
#include<stdio.h>
int main(){
return 0;
}
[/sourcecode]
[sourcecode language=”cpp”]
extern "C" {
……
int __attribute__((__cdecl__)) fscanf (FILE *, const char *, …) __attribute__ ((__format__ (__scanf__, 2, 3)));

int __attribute__((__cdecl__)) printf (const char *, …) __attribute__ ((__format__ (__printf__, 1, 2)));

int __attribute__((__cdecl__)) scanf (const char *, …) __attribute__ ((__format__ (__scanf__, 1, 2)));
……
}
[/sourcecode]

The output of preprocessor use extern “C” to enclose all standard C library function declaration. However, you will not be able to find extern “C” if you change file extension to .c. Stanfdard library uses following trick to do this:

[sourcecode language=”cpp”]
// /usr/include/sys/cdefs.h
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
#else
# define __BEGIN_DECLS
# define __END_DECLS
#endif
[/sourcecode]

All C library header files include this “cdefs.h”, and use __BEGIN_DECLS and __END_DECLS to enclose function declarations.

Nasty C code

Today, my friend Yuan Yuan showed me a piece of C code, which gives different result under different optimization option. I was greatly surprised that such code exists.
His original code is complicated. I minimized the code in order to demonstrate the problem.
[sourcecode language=”cpp”]
int main() {
int i=0;
int a[2]={0};
a[i]=++i;
}
[/sourcecode]
[sourcecode language=”cpp”]
int i=0;
int main() {
int a[2]={0};
a[i]=++i;
}
[/sourcecode]
This two piece of code will give different result on windows 7 Professional, compiled using MingW’s g++ 4.50. More specifically, in the first program, a finally becomes [0,1], while in second one, it is [1,0].
Let’s look at the assembly code generated by compiler:

	incl	12(%esp)		# i++;
	movl	12(%esp), %eax		
	movl	12(%esp), %edx
	movl	%edx, 4(%esp,%eax,4)	# a[i]=i;
	movl	_i, %eax		# int temp=i;
	movl	_i, %edx
	incl	%edx
	movl	%edx, _i		# i++;
	movl	_i, %edx
	movl	%edx, 8(%esp,%eax,4)	# a[temp]=i;

Comment is equivalent C code. We can see that they are doing completely different things. I am not sure which one is correct behavior of ++ operator, or even the behavior of ++ operator is undefined in this case.


The lesson is: never write code like a[i]=i++.