Related
I'm looking for a higher-level system language, if possible, suitable for formal verification, that compiles to standard C, so that it can be run cross-platform with (relatively) low overhead.
The two most promising such languages I've stumbled during the past few days are:
BitC - While the design goals of this language match my needs (it even supports the functional paradigm), it is in very unstable state, the documentation is out of date, and, generally, it seems like a very long shot for a real-world project.
Lisaac - It supports Design-by-contract, which is very cool and has a relatively low performance overhead. However the website is dead, there hasn't been a new release since '08 and generally it seems the language is dead.
I'd also like to note that it's not meant for a real-time system, so a GC or, generally, non-determinism (in the real-time sense), is not an issue.
The project involves mainly audio processing, though it has to be cross-platform.
I assume someone would point me to the obvious answer - "plain ol' C". While it is truly cross-platform and very effective, the code quantity would probably be greater.
EDIT: I should clarify that I mean cross-platform AND cross-architecture. That is why I consider only languages, compiled to C in the first place, but if you can point me to another example, I'd be grateful :)
I think you may become interested in ATS. It compiles to C (actually it expresses and explains many C idioms and patterns from a formal type-theoretic perspective, it has even been proposed to prepare a book of sorts to show this -- if only we had more time...).
The project involves mainly audio processing, though it has to be cross-platform.
I don't know much about audio processing, I've been mainly doing some computer graphics stuff (mostly the basic things, just to try it out).
Also, I am not sure if ATS works on Windows (never tried that).
(Disclaimer: I've been working with ATS for some time. It is bulky and large language, and sometimes hard to use, but I very much liked the quality of programs I've been able to produce with it, for instance, see TEST subdirectory in GLES2 bindings for some realistic programs)
The following doesn't strictly adhere to the requirements but I'd like to mention it anyway and it is too long for a comment:
Pypy's RPython can be translated to C. Here's a nice talk about it. It's been used to implement Smalltalk, JavaScript, Io, Scheme, Gameboy (with various degree of completeness), but you can write standalone programs in it. It is known mainly for its implementation of Python language that runs on Intel x86 (IA-32) and x86_64 platforms.
The translation process requires a capable C compiler. The toolchain provides means to infer various things about the code (used by the translation process itself) that you might repurpose for formal verification.
If you know both Python and C you could use cython that translates Python-like syntax to C. It is used to write CPython extensions.
After five years of professional Java (and to a lesser extent, Python) programming and slowly feeling my computer science education slip away, I decided I wanted to broaden my horizons / general usefulness to the world and do something that feels more (to me) like I really have an influence over the machine. I chose to learn C and Unix programming since I feel like that is where many of the most interesting problems are.
My end goal is to be able to do this professionally, if for no other reason than the fact that I have to spend 40-50 hours per week on work that pays the bills, so it may as well also be the type of coding I want to get better at. Of course, you don't get hired to do things you haven't done before, so for now I am ramping up on my own.
To this end, I started with K&R, which was a great resource in part due to the exercises spread throughout each chapter. After that I moved on to Computer Systems: A Programmer's Perspective, followed by ten chapters of Advanced Programming in the Unix Environment. When I am done with this book, I will read Unix Network Programming.
What I'm missing in the Stevens books is the lack of programming problems; they mainly document functionality and provide examples, with a few end-of-chapter questions following. I feel that I would benefit much more from being challenged to use the knowledge in each chapter a la K&R. I could write some test program for each function, but this is a less desirable method as (1) I would probably be less motivated than if I were rising to some external challenge, and (2) I will naturally only think to use the function in the ways that have already occurred to me.
So, I'd like to get some recommendations on how to practice. Obviously, my first choice would be to find some resource that has Unix programming challenges. I have also considered finding and attempting to contribute to some open source C project, but this is a bit daunting as there would be some overhead in learning to use the software, then learning the codebase. The only open-source C project I can think of that I use regularly is Python, and I'm not sure how easy that would be to get started on.
That said, I'm open to all kinds of suggestions as there are likely things I haven't even thought of.
Reinvent a lot of the core Unix utilities. Most of these were (and still are) written in C, so they are a good way to start off learning. Depending on your skill, pick harder or easier utilities to copy.
Try writing your own malloc. You'll learn a lot about Unix and a lot of C programming as well.
Google for computer science operating system courses and do the projects there. Many schools have these projects on public websites so you could get everything you need. Here is a link to Purdue's site. Give the shell project a shot; it was difficult, but really educational.
Here are a few stackoverflow postings discussing C/Unix programming books. Their main claim to fame is extensive fan-out to other resources.
Practice some of the idioms (understand the ins and outs of pointers etc) and pick projects that help with that. The third item in the list has an answer (disclaimer, I wrote it) with a bunch of high-level C idioms where an idiomatic C program would differ from Java.
Learning XLib or Win32 GUI programming with C is probably less useful as almost anything is better than C for GUI programming and wrapping a core C engine with another language is generally much easier - unless you're really concerned with speed. As a starting point, concentrate on 'systems' programming applications, which is where you are most likely to get real mileage from C. Learn how the C interface of one of the scripting languages like Tcl or Python works.
Writing some bit-twiddly and pointer heavy code (e.g. picking apart network packets or interpreting a protocol), or server-side items using sockets will take you right into C's core competencies. If you've got some of the WRS books, try making pthreads work (IIRC UNP2 has a big section about pThreads). For a contrast, write something that uses non-blocking I/O. This stuff is C's home turf and you'll get a good working knowledge of C by doing this. Troll through the RFCs for some ideas of network protocols to implement.
What are good Linux/Unix books for an advancing user?
What are some good resources for learning C beyond K&R
Resources for learning C program design
What’s a good way to start learning about Data Structures & Algorithms?
Algorithms in C
Are you open to book suggestions? Although it is a bit dated (where "a bit" perhaps is a huge understatement), Maurice Bach's "The Design of the Unix Operating System" is a great book. It belongs next to K&R on your bookshelf.
You might try working your way through all the examples in the book Software Tools (Amazon). Much of it is pretty pedestrian (right-justify text, de-tabify, etc.), but it's a great introduction to the Unix philosophy and basic C programming.
This is pretty interesting. As we know that Unix is designed by using the C language, it may not difficult to learn. If you are using the Windows OS, you can use a "Windows services for Unix" application to practice your programs. If you are using Unix, then we can use editors like vi.
I would recommend one thing highly.
Try and re-write all usual Linux command lines tools like ls, mkdir, cd etc.
You'll gain a lot of knowlege about programming and Linux both at the same time.
Pick the commands from the easiest, say "time" and work all the way up to the more complicated ones.
The best way to consolidate your learnings it to practise. So just choose a kind of application that interest you and start developing it (for example, a network client/server simple application).
Try to test most of the Unix APIs (files, sockets, etc.) to see how they work. You could for example get an Unix programming book, follow its chapters and test on your application everything you read, by creating your own functions. On that way, you can start to develop your own function library to be used in further projects.
Write a webserver.
Make it multi-threaded.
Have it support a new scripting language you develop (a la PHP, etc.)
Allow uploads from authenticated users.
Write a plugin for your favorite tool (i.e. integrate with SVN to give a webview).
This is not meant to be inflammatory or anything like that, but I am in the midst of learning C, and (think) I have a good handle on most of the basics. I've done all of the various book exercises: primes generators, Fibonacci generators, string manipulation, yadda yadda, but none of this is cool.
What is the "bridge" between command line programs and something -cool-? I've heard of various games being written in C, but how?
Forgive my exasperation, but it feels like I've been learning lots but can still only do relatively little. Thanks for any insight on what to do with C.
Relevant information: OS X leopard, PHP and web development experience (which is so great because projects are immediately in a context where you recognize how they can be powerful)
C is the concrete and the steel of modern tech
There was a time when almost everything was written in C, or in something much worse.
These days, many of the advanced languages and systems are actually implemented in C or C++, and then those things implement more systems. It is standing on the shoulders of giants, as the expression goes. Almost every OS kernel, browser, and heavy-duty-web-server is written in C/C++.
So sure, you don't see the steel in the high rise, you see the beautiful interior furnishings and the sleek glass windows. You don't want a steel or concrete desk, and if you did, it would be too expensive to build for you.
Back to your GUI question: your first C graphics program should probably use the original X Window System directly. Don't spend too much time there, but then move on to one of the more advanced Widget toolkits such as GTK+ or (the C++) Qt. Be sure to investigate your OS X system, as it has one of the most advanced of them all.
I try love to write things in Ruby these days, but I happen to know there are over 100,000 200,000 lines of C code implementing that cool Ruby language system. :-)
Summary
Ok, this post got really big, so here's a quick summary before you read it: to program GUIs, there are a number of good C/C++ libraries (for example, QT). What most people do, on Windows systems at least, is to use a .NET language (like C#) when they want GUIs, and C/C++ when they want more control/speed. It's also very common to use both in combination, i.e. make a GUI in C# and speed-critical parts in C.
I still encourage you to read the longer answer, it contains a lot more information on your options.
Longer answer
I'll start with the big question, then answer (as best I can) your specific question about creating a GUI. I think you're kind of suffering from the fact that C is used to teach programming, and it's much easier to do so only using command line programs (after all, they're much simpler to write). This doesn't mean that C can't do all of the stuff you want, like GUIs specifically. It does. I don't think there's any type of software that hasn't been done in C, usually before it was done in other languages.
All right, some answers:
Is C Useful?
C, and its very close relative C++, are responsible for a huge portion of the world's code. I don't know if more code is written in C than any other language, but I'm guessing it's not far off.
Most of the really important programs you use are actually written in C/C++. Just for one example, Windows.
Where is C used today?
C/C++ are still used a lot. They're especially useful for developing low-level stuff (i.e. stuff like Operating Systems, which need a lot of speed, a lot of ability to control exactly what your code does, etc.).
But don't think it's all low level for C programmers. Even today, with many other languages available (which are arguably much better, and certainly much easier to program), C is still used to create practically everything. GUI applications, which you specifically asked about, are very often made with C, even though nowadays, lots of people are switching to other languages. Note I say switching: C used to be the standard language for writing, well, everything, really.
How do I develop GUIs with C
Alright, you specifically wanted to know how to create a GUI with C (I'm hoping C++ is ok too).
First of all, it depends on a number of factors:
What Operating System are you writing for? (Windows, Mac, and Linux are the most common).
Do you want the GUI to work on other systems as well?
The most common case is writing software to work on Windows. In that case, the "natural" solution is to write things that work with the Win32 API. That's basically the library that "comes" with Windows, letting you do any GUI work you want to do.
The big problem with this is, it's kinda hard. As in, a lot hard. This is the reason most people don't do that kind of work anymore.
So what are your other options?
The most natural is going with what's called a .NET language. Those are a bunch of languages, together with libraries, that Microsoft created. They're probably the easiest way to get a GUI on Windows. The problem is, you can't really use them from C (since it's not a .NET language).
Assuming you want to stay in C/C++ land, you can use some kind of library which makes working with the Windows API easier (since it hides all the ugly details):
One of the most common is what's called MFC (Microsoft Foundation Classes), which are a bunch of C++ classes which make it "easier" to create Windows stuff. Unfortunately, this library is very old, and is really not that easy to use.
The other way to go if you want to program in C++ is to use some kind of third-party library. This is a library that someone other than Microsoft created, which makes it easier to create a GUI.
Another option is to create only the GUI part of your software in a .NET language, and use C/C++ for the other parts (or use the .NET language to do almost everything, and use C/C++ only when you really need it, for example when you need things to go really fast). This is a very popular option.
The advantage of a third party library is that, if you pick the right one, you can use the same code to create a GUI for all the Operating Systems at the same time.
I think the most famous of these libraries is QT, and also WxWidgets, but there are a bunch of other ones. I would personally pick QT since it seems to get the most fame, but I haven't worked with either.
Every major operating system has all of its low-level libraries implemented in C. Mac OS X is a Unix-like system under the hood, which is a wonderful world if you're a C programmer.
Check out The Art of Unix Programming for some great ideas.
As for GUI stuff, you'll probably want to use X11. There is plenty of good documentation out there -- most Unix programming stuff and most deep system-level stuff just assumes you're working in C, since that's what everybody uses for it.
Well, that depends. If you want to build desktop applications, a multiplatform GUI library whose main language is C is GTK+:
http://www.gtk.org/
For games, check out SDL:
http://www.libsdl.org/
Which provides you with thinks like direct input from keyboard, 2D graphics, some audio and even threads and stuff like that. It can also open an OpenGL context if you want to get into the 3D world (however it's hard to do it in raw OpenGl). Did I mention that SDL is multiplatform?
However the real strength of C is in systems programming. For desktop applications/games maybe you are best suited with C++. Now that you have command of C, learning the basic C++ should be easy ;).
Cool stuff do with C?
Operating Systems, device drivers, and python modules for starters.
Games typically will use C++ if they're C-Based, in my experience / what I've seen.
There are many libraries for C under Unix, such as X lib, which accesses X11.
If you wanted to get into robotics you may find C to be very useful, as you will have to write low-level code with very small memory footprints, so even C++ may not be the best choice.
C and C++ are very good at writing small, fast code, but OOP is not always the best choice, so at times you will find that C is a better choice, for example if you are writing a compiler or OS.
Sure there are some impressive programs made in C !
GNOME for example, arguably the most used desktop environment used in modern unix systems is written in C (the major parts at least) and is mostly based on GTK+ gui toolkit, itself done in C.
For game, OpenGL is a C api and is the standard for 3D graphic programming in multi-platform development (not uniquely microsoft platform), and Quake 3, which the engine, Id Tech 3, is available in GPL, is also writen in C. There also is many 2D games written using SDL library.
SDL is a good library for graphics and sound, and I've seen some cool stuff done with it. If you do it in C, it'll take longer to make, but from a performance point of view, it'll be much better.
If your idea of cool is GUI apps and you want to write native GUI apps on the Mac, you'll want to look at
Carbon. This is the official C API into the Mac GUI and OS. They keep threatening to kill it, but it survives.
Personally I think GUI apps are a very narrow definition of cool. What I think is cool is implementing parallelized math algorithms using opencl.
GTK-server is REALLY easy to get started with, in C or any other language. Just click that link.
For a "cool" application that goes beyond simple GUI's, check out the OpenCV computer vision library. It provides fast real-time image processing and face recognition.
Now you can access a webcam and start writing real-time computer vision games. For applications like these that are processor intensive, C is the ideal choice.
Last I checked more Open Source projects are started in C than in any other language.
The fact that C is used by so many large and successful projects doesn't particularly make it "good". The reason C is so commonly used is because of a few factors, it's been around a long time, it's fast, it lets you access both low level and high level interfaces as needed, and it's better than the other old languages (FORTRAN etc). The "cool" thing about C is that you can make it do absolutely anything: inject itself into the kernel and add some new features or bug fixes that you couldn't convince Microsoft to do, etc.
Yes, C can be and is easily used for things beyond the command line, but it's extremely dangerous due to pointers... Not to mention development in other more modern languages is faster (and safer) by magnitudes. I never use C unless it's the last resort, ie: need to implement something low level or needs that extra performance.
By the way, when I say C, I really mean C++. I'd never choose C over C++ unless I was forced to.
Once upon a time, a team of guys sat down and wrote an application in C, running on VMS on a VAX. It was a rather important undertaking and runs a reasonably important back-end operation at LargeCo. This whole shebang works so well that twenty-five years later it's still chugging along and doing it's thing.
Time passes and people retire and it so happens that the Last Man Standing has turned over the keys to a new generation who - we might imagine - are less than thrilled to find themselves caretakers of a system old enough to be their younger brother. Yet, as underwhelmed as they are by the idea of dealing with Ultra Legacy Systems, they can't justify the cost of replacing the venerable application.
LMS discovered that I habla unix and put this question to me. And since I habla unix but don't speak the C I shall summarize and put it to you. Long Story Short:
LMS wants to port LegacyApp, written in C. from VMS to unix. Resources? Any books he can read? People he can talk to?
The first question I'd need to ask is why, and I'd be leading the conversation in the direction of "Do you really need to port it off of VMS". There are a number of things worth mentioning about VMS:
-> VMS is still actively developed and maintained by HP. They just release V8.4 for Field Test last week (see http://h71000.www7.hp.com/openvmsft/).
-> VMS is available on new hardware; specifically HP's Integrity servers based on the Itanium processor.
-> VMS is also available on virtual platforms via the Charon Emulation products.
-> Popular estimates are that there are about 300,000 VMS systems still in active use today. LMS may be the last man at LargeCo, but he's far from the last man standing worldwide.
-> Lots of information out there, see openvms.org for example, to see lots of current information on VMS, all from current users.
OK - you still want to port off of VMS. How do you do it? Well, it depends on lots of stuff.
-> As others have said, how standard is the code? Chances are, not very. The more VMS-isms, the more difficult the job. 'nuff said.
-> What is the database? If it's Oracle, probably not too tough to move to Oracle on some other platform. If it's some sort of custom DB based on RMS index files, then you've got more work to do, you'll need to re-create that pseudo DB, or, understand it enough to replace it with some relational DB.
-> Besides C, what else is used to create the application? What's on the front end? DECforms? FMS? Is there a transaction engine, e.g. ACMS? RTR? These things will have a huge impact on the feasibility and effort required to port to UNIX.
-> What other products are involved? Are there any 3rd party libraries being used? Are there 3rd party products in use that are critical to the application or functionality?
-> Is this system clustered? If so why? You'll need to meet those same goals with the UNIX box.
-> There are companies out there that will help you do it, and claim to have tools to make it easier, but my experience is that these companies tend to be selling you more services than products (i.e. you need to hire them to use the tools. It'll be expensive).
The book UNIX for OpenVMS Users will give the VMS novice some help in understanding VMS, but, as the title says, the book is really intended for the opposite purpose.
Everything written on VMS uses lots of VMS specific stuff it was just so convenient.
There are a few companies that sell compatibility libs to make the port easier - they wont be cheap though, VMS tended to be used where reliability mattered more than cost.
The other option is to run openVMS on some modern hardware, possibly in a VM.
I am sure Brian has made his decision by now, but for my sins of working for many years in DEC OpenVMS language support (yes, some people had this dubious honour) the real question I would have asked a customer such as Brian is: is it a real-time application or not? If it is the former, then it would be heavily dependent on many VMS system services which would rule out a 'port' and indicate a re-write. If it were the latter then the frequency of VMS system services should (possibly) be limited and make a port viable.
The acid test for me, would be to SEARCH *.c "SYS$", "LIB$" i.e. to search all of the C source files for "SYS$" and "LIB$" tags which prefix VMS system services. If the count for these are in the 10s then a port is probably likely, between 10 and 100 makes it possibly likely, but over a 100 makes a successful port highly unlikely.
Hope this helps
You have several choices.
Get the OpenVMS source, and continue to maintain Open VMS as if it were a Linux distribution. Some folks don't mind keeping up with Linux distributions and OpenVMS distributions. It can be done.
Try to recompile the VMS C into Linux. This can be trivial if the C used only standard libraries. This can be very, very difficult if the C used a lot of VMS libraries.
Once you have facts at your fingertips, you can reevaluate this course of action. Since you didn't list a bunch of VMS library methods this program uses, it's impossible to tell how entangled it is with the OS.
This may be trivial or impossible. It's difficult to tell without analysis of the source.
Write bridge libraries from VMS to Linux. If your program only does a few VMS things, this isn't very difficult. If your program does extensive VMS things, this is craziness.
The bridge -- in the long run -- is a terrible idea. Managers love it, however.
An alternative is to replace the VMS library calls with proper, portable Linux calls rather than write bridges. This is better in the long run, because it excises the non-portable features of the program.
Rewrite it from scratch in Python. That is usually simpler than trying to port the C code. It will be shorter, cleaner, simpler, and portable.
If you're willing to keep running VMS in a VM, you can look into CHARON-VAX ( http://www.charon-vax.com/ ). As previously mentioned, the ease of porting really depends a lot on how much of the VMS extensions were used; searching the source code for $ characters embedded in strings (usually with a 3-character leading substring, such as lib$gettime or dsc$descriptor or sys$foobar etc) will give you at least a basic idea of what VMS system functions are called and how likely they are to be portable, if the name is reasonably obvious.
If it ain't broke, don't fix it! Why port it or migrate the app if you don't have to? Why not run it on a current install of OpenVMS running on an HP Itanium server; that is assuming you wish to upgrade the hardware, which may not even be necessary if your VAX hardware is still running strong.
To learn C, you might as well drag it from the horse's mouth: "The C Programming Language" by its inventors, Kernighan and Ritchie.
I can recommend "The UNIX programming environment" by (again) Brian Kernighan; a more authoritative source you'll hardly find, and it teaches you both Unix/C idioms and a bit of C programming at the same time.
For more depth and detail on C, I heartily enjoyed a book by Peter van der Linden: "Expert C Programming - Deep C Secrets".
You'll also want to wrestle LMS for a library documentation of VMS-specific C functions with (of course) special emphasis on those actually used in the app. That's where your porting effort will be.
The job could be easy or difficult, depending on how much machine-specific cleverness and bit-twiddling is done, and how many VMS-specific system calls are used. It would be very good if word size was equal (in other words, if your VMS box has a word size of 32 bits, don't run the code on a 64 bit version of Unix!)
Brian, I'm not sure if LMS specified/cared to port C-code or the WHOLE process. As too often people think of languages out of scope of systems.
If there're was a process built on VMS, most likely it used at least scheduling/batch facilities, which are often scripted in DCL (rather simple and clear language, unlike shell or perl scripting).
So the cost of porting the whole process may be higher than originally perceived by your LMS. Add here the reliability aspect, given your crunches with C, which is nothing impossible, of course, with enthusiasm and determination.
If you want simply give the C-code a try, as previously posted, search it for the "$" hits. Or just cc it with all headers present, the basics of compile-link command should be enough.
Alternatively, this looks like a consultant's call, as indeed such jobs were abundant at the "exodus" time. All said VMS remains quite a robust platform (24x7 is a norm!), unless the harware dies, then there're still tons of "exodus" spares. GOOD LUCK!
About a year and a half later, maybe you've already figured out what to do. My organization has recently decided to stick with OpenVMS instead of switching to Linux even though the old guard recently left. We just couldn't argue with what we felt was a very stable and reliable system. We are currently switching from Alpha servers to Integrity servers for end of life reasons. HP has been very helpful with our transition.
For that matter, there may be Linux vendors out there who can help with the transition. Ask your new hardware vendor if they have any recommendations.
Depending on what languages you already know, C is not that hard to learn. I taught myself C in the course of learning C++ after finally prying myself loose from Pascal.
(VAX Pascal, plus Rdb/VMS, plus DCL formed a combination that was hard to beat.)
If the software is typical C, you'll spend more time learning the library functions than learning the language.
It's pretty lightweight stuff, but I went through the online tutorials for C++ that Microsoft makes available in conjunction with the express edition of Visual Studio for C++.
Here's the beginner's tutorial:
http://msdn.microsoft.com/en-us/beginner/cc305129.aspx
It's probably worth making the effort to ask why LMS wants to port the application to Unix. The answer may seem obvious, but properly exploring the reasons has its benefits. I would assume:
OpenVMS is an "ultra legacy platform", and for that reason alone is something that is not worth running an application on anymore;
It's tough to find anyone who is willing to maintain an application that runs on OpenVMS these days;
The hardware on-which OpenVMS runs is threatening to become moribund.
We have a similar challenge, but in our case the application in question not only runs on OpenVMS but is also written in COBOL. I would have to say that your situation is rosy in comparison given that your application is written in a cross-platform language.
In any case, I think if you're about to make a big decision like moving from OpenVMS to Unix it would be prudent to do a little due diligence. In your case, try to assess just how portable the code is--only then will you know what the scale of the effort is (worst case could quite easily be a multiple of best case). In C, code portability is mostly a function of the dependencies--are they "standard" or are they VMS-specific?
Our enquiries revealed that HP would be supporting OpenVMS on Itanium until at least 2022. There isn't necessarily a need to rush to another platform--perhaps you could keep things on OpenVMS whilst embarking on an effort to prepare the application for porting (make it less dependent on OpenVMS specifics).
VMS has a surprisingly healthy community and if it's the lack of Unix that's the issue, then maybe GNV could help bridge the gap?
Well u have a few options. if this code needs to be ported rather quickly, i would write a bridge library to emulate the vms libs. whener you get it back up and running on a *nix, then go through replacing the vms library calls with native/portable calls for *nix.
Also if there is a lot of optimizations in the code ie inline assembly and bit twiddling. then you will have to rewrite thi code, which will take an understanding of the VAX arch. also. be sure to check word size differences and endian differences
I've read 'The C Programming Language', what should I be doing now? Is there anything important in C that's missed out in the book? Specifically interested in the Linux side of development, so is there anything important I should learn about C in Linux? (I already know some of the basics).
I'm sorry if this question seems a bit general, but i'm a little lost as to what to learn next.
Do the book exercises!
Reading it is too little.
I'd start off by actually programming something next. Project Euler has good problems to solve that will help you get a better understanding of the language. From there you can move in to Linux-specific C programming, but definitely get your feet grounded in the C basics first.
The W. Richard Stevens books are the next place to go to, if you're interested in Linux development (they're about general UNIX-alike development, but it's all pretty much applicable to Linux).
Start with Advanced Programming In The UNIX Environment.
Many answers mention actually programming, and I would start by that if you haven't.
I would also recommend reading quality code. Read, say, bzip2's implementation. Do not worry about not understanding everything on the first pass. There are plenty of little things, idioms, ... than one can pick up even without having read about the algorithm that is being implemented beforehand (the algorithm is interesting too, by the way).
If you are interested in program verification, take a look at ACSL, a specification language to write (and verify) contracts for C functions.
Knowing C is cool. How about learning a different aspect than just the language/syntax?
Two things that strike me are:
Socket programming. Write a basic chat client/server. Or a small file-transfer program
Multi-programming. Either with processes (fork(), etc - and this would fit nicely with sockets) or
pthreads. Learn multi-threaded programming, and what makes them different vs processes to get things done in parallel.
Both of these (sockets, multi-programming) are idea for a single project. You could write a networking program (like a shell), and then modify it to handle multiple connections - making use of processes/threads.
If You want deep dive into Linux hacking read already mentioned "Advanced Programming In The UNIX Environment". But IMO this book required some experience before reading it.
I suggest some books about programming tools (used in Linux but not only) like svn, diff, packaging system:
Professional Linux Programming - good book step by step tutorial about creating video rental service using only Open Source tools. Unfortunately it's not only about C and required some knowledge of other languages.
Linux for Programmers and Users - lot of informations for Linux programmers and users
The Linux Programmer's Toolbox - vary good book about Linux tools for programmers.
The Art of UNIX Programming IMO every programmer should read this book, there is a little source code, a a lot of philosophy (some one may don't like it) but most important is it show beautifully of
Unix design, and show how to follow it in your own programs.
Data Crunching: Solve Everyday Problems Using Java, Python, and More Data Crunching: Solve Everyday Problems Using Java, Python, and More] - book not about C nor Linux but it's help to solve data processing task smartly.
Expert C Programming: Deep C Secrets
What's the use in learning things if you're not going to use it. Make a program.
Then when you find you don't know how to do something, look it up or ask here.
The best way to learn is to do.
Understanding Unix/Linux Programming
This book is really good. It basically covers all the OS specific stuff (specific to Unix and Linux) that isn't covered by the C specification.
This book covers things like signals, threads, inter process communication, network programming, and a bunch of other stuff.
In addition to doing the exercises in K&R, I'd start by duplicating a bunch of commonly used linux commands. This is helpful for 2 main reasons.
There are Linux/Unix commands of all levels of complexity. You can start with the easy ones and move on as your skill increases.
You can compare your program's output and running time with the real one to check correctness and efficiency.
Every time I learn a new programming language I duplicate a few linux commands to solidify my ability to solve actual problems in that language.
Reading about programming is a helpful way to get started, but what you read won't really start to come together in that "Aha!" moment until you start to do some programming. Find a task that you need to that could be solved by writing a program (even if that task has already been solved many times) and write a program to do it. The program doesn't have to be composed of pretty or efficient code and the result doesn't have to be attractive. The more you do some programming, the better you'll get and the better your programs will be.