Showing posts with label C. Show all posts
Showing posts with label C. Show all posts

Tuesday, August 21, 2012

C Macros and Let Polymorphism

We use macros for constants quite a lot at work, and it occurred to me that since a macro is replaced at a token level (before parsing and certainly before type checking) and since C will do coercive casting on literals, macros are somewhat like a limited form of Let Polymorphism. Obviously they not the same thing, but in practice you sometimes get the advantages of Let Polymorphism in that you get the same expression at several types.

Thursday, June 28, 2012

Thoughts on C Callbacks

I've come across several examples recently at work of places where a C function pointer can be provided as a callback, and a single argument is (often optionally) provided. The argument is given when the callback is registered, and the function is called with the same argument each time, usually given as an "int". These are just some thoughts about this technique.

First off, the whole "only one argument" is not a big deal. These are essentially higher order functions, and as we all know, one can curry and uncurry functions. Of course, in C this is done by hand, but its still possible and done all the time. It is common to define a struct containing the values for a callback, and passing a pointer to such a struct in the callback to provide multiple arguments. As structs are product types, this is essentially uncurrying a callback of multiple arguments.

The whole "called with the same argument every time" is not really a big deal either- if you want to have a value that changes, just pass it a double-indirect pointer and change the pointer value. This must be done carefully (like everything in C) as in some situations your callback can be used in a context that can interrupt any context that changes the value of its argument, and synchronization primitives may not work the same in the two contexts (ISRs in VxWorks for example).

This is not the only situation I've seen, however. In VxWorks, tasks can have up to 10 arguments when they are spawned. I believe the reason they can be optional is that if ABI specifies that the caller cleans up the stack, the callee not using some extra values is not a problem. I imagine they would have to be placed with the leftmost argument on the top of the stack for this to work, but I haven't peeked around in memory to make sure this is true yet.

Tuesday, November 15, 2011

The Size of an Array in C

Recently I saw a piece of code that looked a little something like this:

void zero_array(char array[])

{

memset(arr, 0, sizeof(array));

}

I have to say, I was surprised by this. How could a program know the size of an arbitrary array? I expected sizeof to always be determined at compile time, and furthermore I wouldn't have thought that the size of an array could be determined at runtime anyway. These aren't forth-style arrays, where the length is stored before the elements- you only have a pointer with no additional information.

As it turns out, C99 added semantics to sizeof such that, given an array as an argument, the size can be determined at runtime in the right circumstances. This is because a chunk of allocated memory has some (implementation specific) information associated with it by the memory manager.

This of course means that this will only work on pointers returned from the memory manager (or of a static size), which can't be expressed by the type and is entirely implicit in the structure of the program. I'm not sure I would use this very often, especially if I didn't have strict control over the origin of a pointer, but its interesting and possibly useful, and I wanted to record it here for future reference.