

Ask HN: Tips for maintaining a C codebase? - shortlived

My team has a small but growing C library. We have a set of coding and naming conventions that are generally followed and things are fairly modular. Most of us are not C programmers though, so I want to continue reading and learning from other code to bring in useful ideas to our code base. Thanks in advance.
======
tptacek
Wrap your libraries up in ADT-style interfaces.

Give every such interface a _create() and a _destroy() method.

Have _destroy() either return a pointer (which will always be NULL), or
(better, I think) take a pointer-to-pointer so that it can zero the pointer
out after destroying the object.

Don't check malloc; instead, rig your code up to detonate if malloc ever
fails. Checked allocations create rats nests of error handling.

Have a common hash table, a common binary tree, and a common list or resizable
array, working on void-star. Don't allow programmers do implement their own
hash table or tree.

Have a common logging library, with debug levels.

~~~
euroclydon
Thomas, You've mentioned that your new-programming-language-exercise du jour
is to write a virtual machine (or microcontroller emulator), right? I'd like
to try that in C. How would you go about writing this in a simple way. I know
I could google this, but I'm worried I'll find results with too many details
and pollute my discovery process.

Really, I'd just like some opinionated answers to the following from anyone
who cares:

1) What is a simple instruction set that I can support?

2) What existing programs are available for that instructions set, or what set
of tools are there to compile to that instructions set?

3) What are the high level tasks that I will need to accomplish to write this
virtual machine?

4) What should I look up or borrow exclusively versus figure out for myself?

Thanks!

~~~
tptacek
1) AVR

2) You'd compile simple C programs, of which there are zillions, rather than
writing complex programs in assembly.

3) Make a struct that captures the state of the CPU: an array of integers for
the register file, a flag word for the CPU flags, &c. Decode instructions (to
a struct or something, which captures all the options of the instruction).
Execute one instruction (pick it yourself): resolve its operands into
temporary variables, execute the logic (almost invariably trivial), set the
appropriate processor flags (overflow, zero, &c), and then store the result.
Test lightly, and then repeat for all the other instructions. Most will be the
same except for a single line of code. Make a big u_char array to represent
memory. Write a HEX file loader, which will take a .hex file and populate
memory with its contents; the GCC toolchain will compile C programs to HEX
files. Now write the code to load an instruction, execute it, set the program
counter appropriately, and repeat. Spend the next 2 weeks debugging.

4) I say, do it yourself. You can get yourself tied up in knots reading all
the different ways to implement a VM. To start with, write a naive VM yourself
with no help. Then go back and read that stuff if you want; it'll make _much_
more sense.

~~~
mechanical_fish
Incidentally, "AVR" == "Arduino", so if you want a HEX file to execute you can
have the Arduino toolkit drive the GCC cross-compiler for you, while you sit
back sipping mojitos. Download the Arduino toolkit, open up the "Blink" demo,
and press "Verify / Compile". Watch the little message window as your code
compiles: Near the end of the process it will cough up a line like this:

/var/folders/4x/cwc9yvnx071_9whsft75cjvc0000gn/T/build8742301187783484704.tmp/Blink.cpp.hex

That file seems like it would be a fun thing to explore.

~~~
euroclydon
Scheew! I think I'll close the nongnu.org tab I have open and go get that
mojito right now. Thanks!!!

------
greaterscope
Two projects you may want to review for ideas are Redis and toybox.

Redis comes to mind because it started out as largely a single file of code
that has since been split and organized into multiple files. The code is quite
approachable; you'll likely understand how most of it works after a day of
causal browsing. <http://redis.io>

Toybox comes to mind because it's insanely modular, and aggressive about code
re-use. The logic can feel a bit dense at times, but he's going for size and
speed. I'm a big fan of Rob's efforts. <http://landley.net/code/toybox/>

~~~
shortlived
On the subject of code reading: are there specific areas of the linux kernel
(or minux or ...) that someone would recommend to read?

~~~
chas
Reading through this book[1] was a really mind-expanding experience for me. It
is an overview of the kernel and doesn't dive into any one part in depth, but
it was extremely valuable for me in learning how to structure a large c
project as the same techniques and ideas are useful for many large projects.

[1] [http://www.amazon.com/Kernel-Development-Developers-
Library-...](http://www.amazon.com/Kernel-Development-Developers-Library-
ebook/dp/B003V4ATI0/)

------
dllthomas
If you've a bunch of bare integers or floats you're passing around with
meaning beyond "number" and you're tempted to wrap them in a typedef to add
some readability, consider wrapping in a struct with no additional elements.
The compiler will boil it away entirely when it comes time to generate code,
but it'll catch it when you mix up the order of arguments to a function and
the like.

