Friday, October 10, 2003

Usually don't post that often anymore ... but I thought I'd add a few C tricks.

#1 : Array Subscript notation in C is commutative ... that is, to access the second character in a string 's' ... you can just easily type in s[1] OR 1[s] !

#2 : ANSI C decided that in addition to the standard that using a function name in an R-value without the parameter subscripts automatically returns the address of that function (that is , say we just type in malloc, instead of malloc() in any assignment),
that any pointer to a function, when given parameter subscripts, should automatically call the function it points to ...

so say we have a function f() that simply returns a random integer,
and a pointer 'pf' to a function that returns an int,

/* then the following will always be syntactically correct: */
int i;
int (*pf)() ;

pf = f; /*assignment */
i = (*pf)(); /* execution */

/* But very soon, in ANSI-C compliant Compilers, THIS will also be syntactically correct ! */
int i;
int (*pf)();

pf = f; /*assignment */
i = pf(); /* execution */

/* and more importantly, THIS will be correct :-D */

struct p {int (*pf)(); int y;} ;
struct p sp;
int i;

sp.pf = f;
i = sp.pf();

And this could lead to even more interesting behavior when messing with function memory ...

#3 : For structs ANSI C defines the offsetof macro, in <stddef.h>
but if not defined it's usually something like this ... not garaunteed to always be portable ...

#define offsetof(type, mem) ((size_t) ((char *)&((type *) 0)->mem - (char *)((type *) 0)))

And this allows us to do neat tricks, like accessing struct members by name at run-time,
with something like

*(int *)((char *)structp + offsetof(struct p, some_field) = value;

Obviously, one would want to use a bit of #define magic to make such code look prettier ... of course, the better alternative is that gcc has a few flags that allow a much more wysiwyg approach to buffers and offsets, which, in combination with unions and structs, will allow you to get away with darn near anything short of blind polymorphism in structs ...

I'm working on that right now ... I know there MUST be a way to do it --
The problem is that in THIS sense, and in this sense alone, C is VERY strongly typed -- all pointers are simply large integers, and if you want, you can even cast an integer to a pointer, but the key is that you MUST cast to SOMETHING, otherwise it won't work.
C Prime will attempt to make a generic pointer type (any error-checking on that should be up to the programmer), so a person could make a struct of doubles and a struct of integers, and will discern the type when using a generic pointer to one of those types ... (the idea is that the type would be discerned at compile-time and some macros would add the proper cast to each such expression) but you'll still have to use unions if you want to make a container that holds both types.