Posts Tagged ‘languages’

Three Things I Love About C

May 12, 2010 20 comments

Like many other coders out there, I am multilingual.

Well, I’m not really multilingual per se… I can speak English passably and I know enough Spanish to make a fool of myself. Obviously, I’m talking about programming languages.

In no particular order, I have (at one time or another) dabbled in Scheme, Pascal, QBasic,, C#, Prolog, Python, PHP, pl/SQL, Perl, Ruby, x86 Assembly, machine code, bash/shell, Java, GLSL, and C++, and C. And probably some others I’ve forgotten.

I like Ruby and Python a good deal but don’t spend much time using them, most of the code I write goes into filesystems or drivers – so not suprisingly, I’m a big fan of C.

Here are three of my favorite things about C, things that absolutely tickle me pink and make me love coding in C.

Inline Assembly

What other language lets you do this:

asm("int $3");

Or better yet,

asm("leal -4(%esp), %ecx");

Inline assembly into C programs gives incredible flexibility and power to the system designer. Of course, in the wrong hands, inline assembly can hose up the system and make software suck. But you can’t deny the raw awesome computing power afforded by being able to inject assembly directly.

The Preprocessor

From macros to textual replacement to conditional compilation, the C preprocessor let’s you do some neat things which I find both frustrating and amazing.

A few stupid examples:

#ifdef __KERNEL__
#define READ_REGISTER(addr) ioread32(addr)
#define READ_REGISTER(addr) call_other_func(addr)

This can be used to support multiple OSes and/or environments without incurring runtime penalties in a common, shared codebase.

#define MAGIC_NUMBER 5
#ifdef __KERNEL__
#define printf(...)   printk(KERN_ERR, __VA_ARGS__)
printf("%d", MAGIC_NUMBER);

Now to be fair, you can accomplish the same thing in other languages – you can define constants in place of magic numbers, and define your own debug printf which detects the environment and does something different based on OS or other factors. But typically other languages push this decision making process into runtime, impacting performance.

When it comes to macros, sure, you can do all kinds of stupid things – for example,

#define MIN(a, b) ((a) < (b) ? (a) : (b))
foo = MIN(var1, func1(args));

If the return value of func1 can vary between function invocations, for example it accesses a shared data structure – you just set yourself up for a big fat race condition that could take you days to hunt down. Good luck with that.

All things considered, the preprocessor provides power and flexibility I’ve often found missing in other languages.


Ok, obviously all the other languages out there have some concept of references or pointers… but C thrives in weird pointer math and pointer calculations. What other language lets you get away with code like

((unsigned char*)dword_pointer)[byte_offset] = byte;

Now at this point purists will usually be panicking and hyperventilating at the sheer craziness of such an attempt – why would ANYONE EVER want to commit such an act of sedition?!! Well, because sometimes you do. Maybe you have code that needs to iterate through an array a dword at a time, but this one function needs to change a specific byte. Heck if I know, point is this kind of flexibility rocks.

Another way this is manifest is in C’s handling of multi-dimensional arrays – or rather, C’s lack of handling multi-dimensional arrays.

int foo_array[5][10]
int bar_array[50];

foo_array[43] = 10;
bar_array[43] = 10;

Both statements above set element 43 (byte offset 172) to 10. C doesn’t complain, because all arrays are really just pointers to virtually contiguous blocks of memory.

For that matter, you can even do the following:

struct foo bar;
unsigned char * wacky_ptr = (unsigned char*)&bar;
*(wacky_ptr + 10) = 5;

Holy crap batman, what kind of blasphemy is going on here? I’m taking a pointer to a struct, typecasting it to a byte pointer, and setting byte 10 of the structure to 5. Why would anyone ever want to do that?!!

Who cares?

Point is, you can. And there are legitimate, actually useful reasons for wanting to do this. Sure, you can abuse this flexibility and write completely useless and unmaintainable code… but in the right hands, this type of flexibility works wonders.

And that really is the crux of the issue for me. C affords you all kinds of power and flexibility not present or possible in other languages. You want to inline assembly and muck around with processor registers? Sure, go ahead, whatever. You want to #define printf to be an infinite loop and confuse the heck out of your coworkers? Why the heck not, it’s your choice Mr. Programmer. You want to do crazy weird things with pointers? Be my guest!

The reality is, C seperates the men from the mice. Coders from posers. The flexibility C provides can be just enough rope to hang yourself – or in the right hands, it can be a powerful tool that creates amazing and beautiful software.

And that is what I love about C.

Next time tune in for what I hate about C 🙂



Categories: Uncategorized Tags: , ,