Showing posts with label c. Show all posts
Showing posts with label c. Show all posts

Saturday, May 22, 2010

Multidimensional arrays with GCC's variable length arrays

GCC's extensions allow you to do some crazy things with multidimensional arrays. For C99, GCC implements variable-length arrays. So a declaration like this:

int matrix[a][b + 1];

Can be passed by reference to a function with this prototype:

void foo(int a, int b, int matrix[a][b+1]);

Or, if you want to get really crazy, you can use forward declarations and change around the parameter order:

void foo(int a; int b; int matrix[a][b+1], int a, int b);

No malloc needed! Much better than the old way.

Friday, March 05, 2010

Funny C tricks

Taken from Bill Rowan's Stanford ACM presentation:

The "downto" operator:

int main()
{
int i = 5;
while(i --> 0) // --> is the downto operator!
{
printf("%d\n", i);
}
return 0;
}

Cast any type to "bool" type (that is, 1 or 0):
!!foo
"Computed goto" (compiler-dependent && unary operator):
void print_loop(int s, int e) {
assert(s < e);
top:
printf("%d\n", s);
goto *( &&top + ( !!(s++/e) ) * ( &&end - &&top ) );
end:
;
}

Sunday, October 25, 2009

Insidious C bugs

Here's a couple novel C bugs that I've encountered recently (using gcc). Man, it sucks when these happen.

1) No compiler warnings when not instantiating structs correctly

The following code will give no warning indicating that you have not, when declaring an array of structs using the curly bracket notation, instantiated all members of the struct:
#include <stdio.h>

int main()
{
struct a_struct {
int a;
int b;
} buggy[] = {
{ 1, 2, },
{ 3, /* oops! */ },
{ 5, 6, },
};

int i;
for(i = 0; i < sizeof(buggy) / sizeof(*buggy); i++)
{
printf("%i: %i %i\n", i, buggy[i].a, buggy[i].b);
}

return 0;
}
Here's the ouptut:
0: 1 2
1: 3 0
2: 5 6
Oops! It would have been nice for the compiler to tell us about this...

2) Forgetting to delete the semicolon when turning an assert into an if statement

Say you have
assert(cond);
But you want to make it an if statement to have a little more debugging output when it triggers. So you change it to:
if(!cond);  /* oops! */
{
dump_stats();
assert(0);
}
Whoops! Now the if statement has an empty body and the block between the curly braces will always execute!

3) Strange things you can't do within case statements

This isn't really insidious so much as annoying -- why are you allowed to do some things inside a case statement (that don't seem to make sense) but aren't allowed to do others (that seem to make much more sense)? For instance:

int main() {
int i = 0;

switch(i)
{
int j = 5; /* fine */
case 0:
char ch; /* error */
break;
case 1:
i = 1;
char ch2; /* fine */
break;
default:;
char ch3; /* fine */
break;
}

return i;
}
Note the semicolon following the 'default:' There's a good discussion of this problem here. Essentially, the first thing after a label cannot be a declaration. The error that the compiler gives here is usually pretty cryptic, too.

Similar links

Tuesday, December 04, 2007

Code formatting

Here are some tools to make your code pretty (in Ubuntu repos):
For indent, I find that the following arguments seem to work well for code I write: -bap -bbb -bl -blf -bli0 -bls -cli3 -di1 -fca -hnl -i3 -ip0 -l80 -lc80 -nbbo -nut -nsaf -nsai -nsaw -psl