brian_jaress ([info]brian_jaress) wrote,
@ 2008-05-17 22:29:00
Previous Entry  Add to memories!  Tell a Friend  Next Entry
Current mood: thankful
Entry tags:c, programming, uh

Two Semesters of C

When I was an undergraduate at UH, they made a big deal about Java being the default language of the department. Unless the class had to have some other language, we used Java.

But so far I've only had one graduate class with Java. The rest have let me use whatever I want1, or told me to use C.

Lessons Learned

I'd used it before, but I'd never used it very heavily. Wrestling with the language for a couple of semesters made me realize a few things. I'm not trying to criticize C here. Every language has pitfalls, and this is really a list of things I wish I had been more aware of.

Valgrind

The good things you've heard about Valgrind are true. It found bugs I had no clue existed. Once I understood and fixed them, I started using Valgrind all the time. Be sure to use it responsibly2.

-Wall

Everyone says to compile with -Wall, and they're right. But they rarely tell you the real reason you need it.

Here's a fragment of code that gcc compiles silently without -Wall, assuming it has the supporting code it needs:

buffer *
new_buffer ()
{
  buffer *buf = malloc (sizeof (buffer));
  buf->capacity = 100;
  buf->used = 0;
  buf->bytes = malloc (buf->capacity);
}

If you compile it with -Wall, it'll say warning: control reaches end of non-void function. That's because the function is declared as returning a buffer *, but it has no return statement. You can fix it by adding return buf; right before the closing curly brace.

There are languages where you don't declare a return type at all -- you either return something or you don't, and if you forget to do it then it won't happen. That's not surprising. But if you declare ahead of time that you will return a buffer *, you sort of expect the compiler to complain if you don't actually do it.

Use -Wall because it adds the checks you probably assumed you already had. A lot of things suddenly start doing what they look like they're supposed to do.

C Turns Almost Every Error into a Memory Error

If you ran that buggy buffer code, you would have a memory leak. You would also probably have a segfault when you tried to use the buffer.

What happens, as far as I can tell, is that if you call the function you get the value of the last expression. In this case, buf->bytes coerced into a buffer *. So you think you have a buffer, but you really have 100 bytes. The capacity and number of bytes used are now inaccessible. When you think you're accessing the capacity or the number of bytes used, you're actually looking at two values in the 100 bytes. When you think you're looking in the 100 bytes . . . you're probably segfaulting.

When I make an equivalent mistake in most other languages, I get a message telling me I forgot to return something or that I'm trying to check the capacity of something I don't have. In C it's a memory error.

In C, almost everything is a memory error3. I'm actually happy to see wrong output because it's not a segfault. Thank goodness we have Valgrind.

Software Engineering

Software engineering was quite helpful. Especially helpful were ADTs, encapsulation, unit tests, and assertions.

C actually comes with assertions in a header called assert.h. I highly recommend it (to people already using C). C programs tend to be full of assertion opportunities.

For the unit tests, I just had a test module with its own main function and compiled two different programs (through two different make targets) one using the real main and one using the test. I'm not sure if that's the typical way.

Next Semester

More C? I don't know. It's sometimes hard to tell whether a class is going to have any coding at all.

But it's not a bad little language. If you're a real C programmer, any helpful pointers are welcome.


  1. Usually Python. I spent a long time thinking I didn't have a favorite language, and then one day I realized I did and it was Python.

  2. This should go without saying but apparently doesn't: Only fix bugs detected by Valgrind, or in any other way, after you have confirmed the bug and understand it. You could easily screw things up.

  3. On the flip side, I've had almost no trouble with malloc and free. The problem (for me) is not manual memory management, it's the memory model.




(22 comments) - (Post a new comment)


(Anonymous)
2008-05-19 12:00 pm UTC (link)
Hey, I'm a ICS major at UHM as well (undergrad.) Aside from the 111/211 classes, I haven't had to use Java anywhere. I'm not sure why they even teach it in the introductory classes anymore - it seems to me that either C/C++ (for future usefulness), Python (better teaching language) or Haskell (better correspondance with discrete math) would be more appropriate. I've noticed that the professors have a tendancy not to change their syllabi from semester to semester, so it could be just the resistance to change which keeps Java afloat.

(Reply to this)


[info]gonzopancho
2008-05-19 12:19 pm UTC (link)
Hi,

You seem to know some things about UHM, and lisp. I saw your post on "2 Semesters of C" that made it to reddit.

I'm attempting to enroll in UH(M) after a 28 year career writing 'C'. We'll see if I get in (I've not heard back yet.) Part of that was being at Sun (working for Bill Joy) when 'Java' was 'Oak'. I can tell you that Oak was an attempt to fix several things that make 'C' dangerous to use in large programming teams, or in the hands of the neophyte.

Several of these are detailed in this: <http://www.literateprogramming.com/ctraps.pdf>

(which used to be a real-world book.)



As far as your program goes:

You could just sent a command-line flag (./foo --test) to make your program run the test mode, with a fall-through if the flag isn't set. That way you only have one binary.


(Reply to this) (Thread)


[info]brian_jaress
2008-05-20 12:08 am UTC (link)

Thanks, that's a nice article.

The ICS department can take a long time on admissions. I actually joined UHM as an unclassified graduate student (meaning I had no official department) and took ICS classes while the department did whatever they do with applications. It was almost the end of my first semester before they got back to me and said I was officially in.

They'll almost certainly let you in. Even if they think you're missing something an undergraduate should know, they just let you in and have you take that undergraduate class.

(Reply to this) (Parent)(Thread)


[info]gonzopancho
2008-05-20 01:17 am UTC (link)
errrrr. I'm applying for undergrad.

(Reply to this) (Parent)(Thread)


[info]brian_jaress
2008-05-20 01:58 am UTC (link)
Oops. Sorry.

(Reply to this) (Parent)


(Anonymous)
2008-05-19 12:25 pm UTC (link)
For the test applications you can include the headers to just the functions you need to construct a test environment, run the test, and return the result. Have the main in your test program return a 0 on success, and anything else on failure.

You can also read up on autoconf and automake because although it might seem like overkill, learning to set up a project with it, even a small one, makes it the most useful for the largest amount of people. If you do this a good thing to try is to investigate how to set up the above mentioned test programs, and run them with ``make check''

(Reply to this)

More C?
(Anonymous)
2008-05-19 12:55 pm UTC (link)
More everything. A common pitfall of current day programmers is they tend to like one language and stick to it; but in the "real world" all languages are used and you should be ready to program in any of them. To be ready, I would say mastering C (really, C++) would be very wise.
I interviewed for a ColdFusion job having no experience, and when I inquired about the language he just looked at my resume and said "if you're half as good at C as you say you are, you'll have no problem with Coldfusion" -- and he was right, it was a walk in the park, and quite fun to use, actually.
So, keep an open mind about languages, and definitely use all error/warning output messages no matter what language you use (you'll usually have to look it up). Each language has their nuances and "do's and dont's".

(Reply to this)


(Anonymous)
2008-05-19 01:22 pm UTC (link)
0x847AE8, 0x463F , and 0xAE6B10
oh yeah, 0x0 can real helpful too.

(Reply to this)

why java is taught
(Anonymous)
2008-05-19 02:07 pm UTC (link)
As a professor in a cs department:
Java is taught because it is the up and coming language of 2000 ;-). Actually it's taught because a) no (explicit) pointers and you aren't supposed to need to understand memory access in it, b) it is object oriented and c) it's in the curriculum and it is very hard to change an official curriculum. Personally I think python is a better teaching language for introducing objects, but java is better than c++ for beginning programmers. (emphasis on beginning programmers - mature computer scientists pick the language which best suits the problem at hand). I push the students to learn several languages and os's as Java/windows is a very limited way of looking at languages and operating systems. In fact, in my grad classes, java is forbidden to make sure the students actually learn another language. (and its hard to do security related systems level programming in java).

(Reply to this)


[info]tryx_
2008-05-19 02:15 pm UTC (link)
There's a long standing "bug" (feature?) in gcc, so that -Wall doesn't cover a few useful warnings unless the optimizer runs, so if you are looking for bugs, compile with -Wall -O.
This will cover stuff like variables used uninitiated or values that are calculated and thrown away which are all signs of potential bugs.

(Reply to this) (Thread)

neednewbed.com
(Anonymous)
2008-05-19 03:16 pm UTC (link)
this should be called "two semesters of Zzzzz"

http://www.painfullback.com/

(Reply to this) (Parent)

Returned value when a function doesn't return a value
(Anonymous)
2008-05-19 04:23 pm UTC (link)
FWIW, in C, if you don't return a value from a function that is supposed to return one, you get an "undefined" value. For most compilers, you just get whatever happened to be in the return registers.

Typically, that is the value that the last function you called returned. In your case, that's what the last call to malloc returned, and that's the 100 bytes. But it wouldn't have to be. Put in some other random call last, and you'll see that value "returned" from a function that doesn't really return anything.

It's more an artifact of register-based calling conventions than anything else.

And yes, -Wall is just plain good engineering.

(Reply to this) (Thread)

Re: Returned value when a function doesn't return a value
[info]gonzopancho
2008-05-19 06:33 pm UTC (link)
In C, if a function is defined as having a return type of void, it should not return a value. If a function is defined as having a return type other than void, it should return a value. Under compilation for strict C99 conformance, a function defined with a return type must include an expression containing the value to be returned. In old(er) versions of C, the compiler would assume that a function for which type was not declared would return int. C99 removed this 'feature'.

In C++, a function which is defined as having a return type of void, or is a constructor or destructor, must not return a value. A function defined with a return type must include an expression containing the value to be returned.



(Reply to this) (Parent)(Thread)

Re: Returned value when a function doesn't return a value
(Anonymous)
2008-05-19 08:52 pm UTC (link)
You are confusing, "What the standard requires" with "How do compilers act in the real world."

What I explained is why he got what he is getting. What you explained is what the standard requires.

(Reply to this) (Parent)

Use The Right Book
[info]hewhotypes
2008-05-19 04:57 pm UTC (link)
Most people who use C think that the K&R book is the best. It is not. The best is C: A Reference Manual by Harbison & Steele. It's just a better book, by several notches. Not slightly better. Much better. Here's a link if livejournal will let me.

(Reply to this) (Thread)

Re: Use The Right Book
[info]gonzopancho
2008-05-19 06:35 pm UTC (link)
those who don't like K&R have failed to understand the zen of C, and are the same dorks who write overly-large software systems.

(Reply to this) (Parent)(Thread)

Re: Use The Right Book
(Anonymous)
2008-05-22 05:00 pm UTC (link)
I like K&R. I used it for years. I just like Harbison & Steele better. It's a more thorough book. I also recommend the "C Puzzle Book" for those who aren't 100% comfortable with all of C's features. It was a great training book.

(Reply to this) (Parent)(Thread)

Re: Use The Right Book
(Anonymous)
2008-05-22 06:55 pm UTC (link)

I like Abelson and Sussman's SICP, but its not about 'C'.

(Reply to this) (Parent)

Re: Use The Right Book
(Anonymous)
2008-05-19 07:49 pm UTC (link)
C++ is essential. C is less so, and mostly necessary only because it is a subset of C++. Pointers, memory, security, performance, data structures, this stuff is all more directly accessible in C/C++ then any other popular language. This is why operating systems are written in it. This is why it is worth you time to learn it well.

What others have said about learning more languages is also true. As developers we will be asked to code in a plethora of languages. Program in as many as you can as this will teach you to think in more elegant abstractions -- each language does it differently and some turn out to be a mess (data structures in C ) and some do it more right (STL/C++, python, etc.

Good luck!

(Reply to this) (Parent)(Thread)

Re: Use The Right Book
(Anonymous)
2008-05-20 07:20 pm UTC (link)
> C++ is essential. C is less so, and mostly necessary only because it is a subset of C++. Pointers,
> memory, security, performance, data structures, this stuff is all more directly accessible in C/C++ then > any other popular language.

you've got smoke pouring out your ass on this one.

Pointers: Lisp has 'em: (what else could car and cdr be?)
security: Lisp beats c/c++ by miles
performance: Lisp is in the hunt with C, and can beat C++
data structures: C doesn't even get started here.

I'm not sure what you mean by memory, I don't think you mean the memory leaks that C/C++ are famous for enabling.

(Reply to this) (Parent)

Bullseye
[info]posborne.net
2008-05-19 11:49 pm UTC (link)
Spot on. I attend an undergraduate university that uses Java for its introductory, data structures, software engineering, and database courses but also uses C/C++ for some other courses. This semester (Programming Languages) in particular has taught me many of the exact same lessons that you emphasized with C.

Valgrind is golden for finding errors and memory leaks... I feel I have underused some of the software engineering principles in working on my compiler project this semester, but there is always room for refactoring (carefully with C code) on this next iteration (implementing functions with recursion).

(Reply to this)

It's a crime
[info]temp_human
2008-05-20 05:00 am UTC (link)
It's a crime that ANY student graduates a CS program without knowing C. And in my opinion, every CS student should also know at least a little bit of assembly.

If you don't understand the machine, you can never be truly in charge of it.

(Reply to this)


(22 comments) - (Post a new comment)

Create an Account
Forgot your login or password?
Login w/ OpenID
English • Español • Deutsch • Русский…