Note...
- ...the standard reserves identifiers with a leading underscore...
- ...the standard reserves macros matching
E[0-9A-Z]...
...for use by the standard or the implementation.
In particular, if should keep this in mind when automating the creation of header guards.
Bad:
#ifndef __EVERYTHING_H__
#define __EVERYTHING_H__
/* ... */
#endif
Also bad:
#ifndef EVERYTHING_H_
#define EVERYTHING_H_
/* ... */
#endif
Good:
#ifndef H_EVERYTHING
#define H_EVERYTHING
/* ... */
#endif
I find this pattern reoccuring (recursively) in C:
void example()
{
resource_t r = get_resource();
if(!r) {
report_error();
} else {
do_interesting_stuff_with_resource(r);
release_resource(r);
}
}
It's nice to handle the error case first, because then the error handling is close to the point of error.
Fun with the comma operator:
if(!p) return fprintf(stderr, "%s: null pointer\n", __FUNCTION__), EINVAL;
Opaque pointers/handles
/* foo.h */
typedef struct foo_tag * foo_t;
extern foo_t make_foo(int);
extern int foo_get_value(foo_t);
extern void free_foo(foo_t);
/* foo.c */
struct foo_tag
{
int value;
};
foo_t make_foo(int n)
{
foo_t handle = malloc(sizeof(struct foo_tag));
if(!handle) return 0;
handle->value = n;
return handle;
}
int get_foo(foo_t handle)
{
if(!handle) return 0;
return handle->value;
}
void free_foo(foo_t handle)
{
if(handle) free(handle);
}
Pointer cast polymorphism
struct base_tag
{
int base_field1;
int base_field2;
};
struct derived_tag
{
struct base_tag base;
int derived_field1;
int derived_field2;
};
struct derived_tag * derived = malloc(sizeof(struct derived_tag));
struct base_tag * base = (struct base_t *) derived; /* equivalent to &derived->base */
do {
int error_code;
error_code = some_function();
if(NO_ERROR != error_code) break;
/* ... */
} while(false);
Back to the Scheme & general programming main page
last updated 2 years ago
#