understand C code

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi!

Although I have written some thousand of lines of C code already, which makes me think I should be able to understand bigger C code, actually I can't. I'm having trouble to understand bigger code with more header and sourcefiles.
Is there a magic way one can figure out what the code is doing, and why?

My current method is to print out all the pages of source and header files, and lay out on the floor so I can see them all at the same time. And then I start figuring out which variable, constant etc. does what.

any idea is appriciated.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A useful technique I've used in the past is to draw a Jackson diagram:

http://en.wikipedia.org/wiki/Jackson_Structured_Programming

It only works if the code was properly written in the first place, though. I once had to port a large application that was prototyped on a PC to an ADI DSP, and was unable to draw a Jackson diagram because the software was badly written. I insisted that the original software engineer rewrite his code, structuring it properly; it took him about a month.

Leon Heller G1HSM

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
And then I start figuring out which variable, constant etc. does what.
Your starting at the wrong end. Start with figuring out the overall program flow, then get more specific from there. Don't worry about the little details until you know where they fit.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you thought about becoming a carpenter? :twisted:

Well written code will tend to have several attributes:

1. Reasonable partitioning. Breaking code into reasonably sized sections based on function helps isolate concepts to a single file.

2. Isolation of variables to only the code that needs it. This is called "data hiding", and is the basis of object-oriented programming. A corollary to this is to use non-local variables for only one purpose. Especially do not use a global variable for different purposes - break the variable into separate variables for however many purposes the original global is used.

3. Placement of the above partitions into separate files. Mixing of partitions in a single file leads to confusion.

4. Limit the use of global variables. While global variables can be useful (and necessary in small memory machines such as the AVR), newbies tend to overuse them. In general, global variables can be a large source of confusion, especially if the original coder avoided...

5. Use of a reasonable variable naming convention. I'm not talking about the oft-despised "Hungarian" notation touted by Microsoft. Instead, variables should give a good description of what they represent. They should also give the reader an idea of where they are defined. Personally I prepend global variables with "g_" (to tell me that the variable is a global) followed by the module where it is defined. For example, g_MainAbortPending tells me that the system has an abort pending, the variable is a global, and that the definition for it can be found in the main module.

6. Perhaps most important, Document and Comment your code! Do not assume that you will know what a function does just because you gave it and the variables incredibly long names. Place comments in the code to describe what is intended to be done. Place comments at the head of every function describing the parameters and expected results. Place comments in the code when it took you more than 5 seconds to figure out how to do what the code is doing.

7. Restrict headers to contain ONLY function and variable declarations! Put implementation of functions, definition of variables and so on in the .c files!

8. Be Consistent! Whatever style you use, stick to it in every file, every line of code, every comment.

There are lots more ways to help make code more readable: consistent indentation is a must; keep your functions as small as possible (multi-page functions lead to confusion), and so on. I will commonly use page-wide "spacer" comments to visually mark the sections of a file. I also picked up a template that forces me to put declarations in one place, local function prototypes in another, exported ("global") variables in another, local variables in another, and so on. Whenever I start a new C code file (or header file, for that matter), I bring in the template and start putting things in their place.

----------

Now, I can assume that this is not your code. And I assume that the above rules were not followed. Here's a list of things you can do to help yourself:

1. Build a dictionary. You want to list every function. You also want to list every variable that has a scope larger than a single function. For functions, list what the function does, which module it is in, and the list of arguments (if your code already lists this, so much the better) For variables, list what the variable is used for and where it is referenced. Well-written editors (Eclipse, Code::Blocks, Visual Studio) have built-in mechanisms for cross-referencing functions and variables, allowing you to jump to the declaration or definition (also called "implementation) of a function or variable. Unfortunately, AVR Studio does not have this ability (that I know of).

2. If the code has bad indenting, reformat the code. There are several freebie programs that will re-indent a code file. WinAVR includes the program indent.exe - check out the manual for how to use it.

3. If the comments are poor or non-existent, add your own!

4. Be sure to use an editor that allows you to have multiple files up at once.

In the long run, if the code is poorly written, uncommented, and gnarly to the max, you just have to take it one step at a time; there are no short cuts. And curse the bastard you put you into this position!

Hope this helps!

Stu

-----------

PS: In the time it took me to write this tome, others have responded with my advice. Maybe my extra wording will help. Maybe not.

PPS: I should also have added Koschi's comments about determining program flow. And maybe special comments about identifying what each timer, ISR and special interface (USART, SPI, I2C, ...) is running and what they do.

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

Last Edited: Sat. May 8, 2010 - 04:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Koshchi wrote:
Start with figuring out the overall program flow, then get more specific from there. Don't worry about the little details until you know where they fit.
I think it depends on the person. Some people can get the flow without sweating the details of variables, constants, etc. Others need the dictionary before they can move on. Either approach is valid, depending on the person doing it.

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Many large programs evolve over time and end up with lots of things that would have been done in a more formal approach had the full specification been available at the beginning. The ideal thing to do is use a disorderly program like you describe as the specification for a rewrite from scratch, but that rarely happens since most folks can't afford the time to do it right.

I've inherited several large programs and then been tasked with fixing a bug or adding a feature. Almost always I do exactly what you say you do, I print it out and lay it all out on a large floor. I usually end up using a lot of tape, scissors, and felt-tipped markers to understand associations. Eventually I identify the relevant sections and either fix or rewrite those. The resulting code is even messier and less organized than the original, but in general a rewrite would bankrupt somebody, so it stays a fragile mess. Microsoft got rich using this software engineering principle. Companies that did their code 'right' never had a chance.

And I can't fault the original coder(s) because I've been in enough projects that I got on in the beginning and had perfectly good specifications only to later find that there were parts I didn't fully understand in the beginning and at about the same time the folks paying the bills start adding features. Pretty soon your Venus starts looking like Frankenstein and you just thank the good Lord that the thing can walk, to heck with pretty.

You can expend a lot of effort learning good software engineering principles and I highly recommend that people do just that. But you'll rarely get to fully apply these except in academic situations. The best reason to learn how to do it right is so that you can predict when a companies policies are taking your group over a cliff and you'll have time to find another job. And it can help you evaluate a potential employer. If they want you to fix some existing software that some 'disloyal bastard' abandoned after costing them $250k - you can ask them intelligent questions to determine just who really pushed the project over a cliff.

It isn't the way it should be, but it is the way it is.

Smiley

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Koshchi wrote:
Start with figuring out the overall program flow, then get more specific from there. Don't worry about the little details until you know where they fit.
I think it depends on the person. Some people can get the flow without sweating the details of variables, constants, etc. Others need the dictionary before they can move on. Either approach is valid, depending on the person doing it.
And it depends of the nature of the program. often you can follow a logic flow from a HW input (often ADC or RS232) to the output (display rs232 etc.)
I like Stu's list, but because you are a C beginner make sure that you can trace you own comments, there will be things you will misunderstand in the beginning

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My two cents:

The ability to understand huge projects (the Linux kernel that I work with a lot springs to mind) very much depends on the quality of the editor you use. Notepad (or the equally crap editor in AVR Studio) simply won't cut it. You need a source browsing editor. That's one that understand the C language and knows that if you put your cursor on a macro you want to see in a small sub window how it's defined or if you put your cursor on a variable of type 'my_type_def' you want to have a window show you how that type, including sub-structs, unions and so on are defined. If it can follow call heirarchy and show you an annotated diagram of call structure all the better.

The one I use most is called Source Insight:

www.sourceinsight.com

Now $239 for nothing more than an editor may sound a lot of money but in a professional context, for the benefits it brings and the time it saves it is well worth it. I have been in contact with a number of large software development companies over the years (Open TV in California, NDS in Israel as just a copule of examples with several thousand software engineers) and I find that most companies have standardised on Source Insight as their chosen editor.

Having said that the Microsoft Visual Studio Express editor is getting almost as good these days and you can download versions of that for free.

On Linux systems when I haven't been able to map source trees to be visible to my copy of Windows based Source Insight I've used derivatives of Red Hat's Source Navigator. There's an "NG" (Next Generation) version which is surprisingly good for open source software.

Source Navigator started here:

http://sourcenav.sourceforge.net/

but has kind of migrated here:

http://sourcenav.berlios.de/

But like I say, for a "free" tool on Windows look at M$ Visual Studio Express, for Linux look at the above links.

Cliff

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I recommend listening to Software Engineering Radio episode 148

http://se-radio.net/

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the great answers. It was a huge help.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For all the reasons Smiley and the others have staded understanding other people's code can be a real bitch, and printing everything on paper can help.

As a little extra:
I have the biggest monitor on my PC I can afford and I have rotated it 90 degrees. Now it's 1200 pixels wide and 1920 pixels high. This really helps in getting a better overview of any code.

PS. most other texts also have more height than width. (PDF's, datasheets, websites). I only move my monitor to the "normal" position for working with photographs or watching movies.

Doing magic with a USD 7 Logic Analyser: https://www.avrfreaks.net/comment/2421756#comment-2421756

Bunch of old projects with AVR's: http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can always leave the monitor stationary, and lay on your desk to read it.

If you need 1920 pixels deep to read source code, you need to do some serious refactoring. Or perhaps use 'folds' in your editor.

I would prefer two or three files open alongside each other rather than above each other.

David.