Where to begin when learning C? Start by making lots of errors
morganwilde.svbtle.com
morganwilde.svbtle.com
I never took "hello world" seriously until I started doing embedded systems work; it's now an extraordinarily important tool for me (I work an anomalously weird number of different environments).
I ended up with a 50 page LaTeX document that barely even scratched the surface, and then work picked up and I never finished it. A "full" explanation would probably be a 600+ page book.
I still think it would be a neat resource to have. We kind of take for granted that the simple "Hello World" is built on 60 years of research, and is anything but simple.
Regardless, I think it's a great idea, and would really give insight as to why things work the way they do, instead of us just seeing Hello World!
It takes on an even simpler program, namely:
int main() {
return 42;
}
But digs in the C runtime, Linux kernel and touches on compilers, linkers and loaders.Hope it's helpful
https://blogs.oracle.com/ksplice/entry/hello_from_a_libc_fre...
http://www.muppetlabs.com/~breadbox/software/tiny/teensy.htm...
http://timelessname.com/elfbin/
A wee bit heavy, but it's comprehensive. It deals with what happens when you run code, how the architecture of the computer works (by and large) including at the logic level:
http://www.amazon.co.uk/Computer-Systems-Programmers-Randal-...
If you want to go lower (and higher).. look at Understanding the Linux kernel for a good understanding of how an OS is put together, with specific examples i.e. Linux.
Code, by Petzold, deals with logic and computers from the ground up. It starts with relays and builds them up into gates and usable arithmetic blocks.
http://www.amazon.co.uk/Code-Language-Computer-Hardware-Soft...
http://www.amazon.co.uk/Understanding-Linux-Kernel-Daniel-Bo...
The physics is fairly simple, at least from a CRT or LED display perspective. Gets more tricky dealing with interconnecting microprocessors because a good chunk is vendor specific.
I think this kind of project is well suited to a guide on how to build a computer from the ground up, starting with logic gates, writing a real time OS and developing a scripting language that will run and compile on it. Then you can skip a lot of largely extraneous stuff and have a solid understanding of how the hardware works.
But if you do finish this, I certainly would be interested in reading it.
That reminds me of JBQ's blog post from shortly after Dennis Ritchie's death: https://plus.google.com/112218872649456413744/posts/dfydM2Cn...
I would love to see that document if you still have it.
Just because it is C doesn't mean you've got a sane libc. Let alone the luxury of a debugger. Just seeing that simple string on the screen/logfile can be a blessed relief.
I had a lot of things wrong. It took me a while to understand the difference between control-D and EOF, for instance (how embarrassing). But the 30 days I spent without a compiler made me think about program behavior.
I'm not saying this is a great way to learn a language, but it can be done.
I keep hearing people complain about K and R being "a terrible book." For me it was perfect: pragmatic, succinct, with great examples and good exercises.
- Brain Kernighan
And that is what anyone who goes through K&R will do: Reading and writing lots of real programs. A simple program is worth a thousand words!
Which unfortunately the majority of technical books just can't get right. Explain the concepts in 5 full dull pages, and then at the end "Hey, checkout this little snippet of code, which by the way does nothing really interesting, but is here to illustrate what the author was talking about :)"
But reading lots and lots of code (from many different sources) will help him pick up idioms and find common & good solutions to specific problems. Even for a smart person, I think it'll take a lot of time and effort to arrive to the cleanest way of doing things.
Of course there's a risk of picking up bad habits, but if you read lots of code, you should eventually develop a feel for what's clean and readable and easy to understand, and what's messy and wrong. This sadly doesn't help with issues like undefined behavior, but you don't learn these just by writing either. For that you need to look into the spec or some other text that'll cover these.
EDIT: I like to think that I'm a fairly good C programmer (having coded nearly all my life, with C mostly), but I still peek into others code all the time to find out how they've solved some things I'm about to do.
It takes a large volume of work to really get into programming, and I think that reading is easier than writing, so it's a fast way to dig in (keeping in mind that feedback is critical - so reading without writing has severe diminishing returns)!
Whereas, the less said about complicated code, the better.
- Neal Stephenson
(The companion book "Programming in the UNIX environment" is the get-you-started guide from the very beginning, although it assumes 1970s terminal defaults)
Edit: Most resources on the Internet are too confusing for beginners. As a matter of fact, people who know C are usually unable to teach C to novices. Good introductory resources for C are rare - which corresponds to C's elitist nimbus.
As part of broader reading it is deservedly a classic. Alone pretty terrifying.
fortunately I wandered into a company that had even less of a clue than me. It's nice to be an expert on day one with only two days' of expertise :)
I learned a hell of a lot in a year. Great year.
In fact, this is how one of the great teachers of CS, Dijkstra, taught computer science.
I have been known to complain about the second edition--the first is the one that I go back to. But it is an absolutely fundamental book for understanding the practicality of programming. I agree with your assessment.
Use your compiler, use it well with all its warnings. Run your programs under valgrind or some such.
For learning, you could also add -ansi, as it will make your compiler be stricter about standards.
Fun post. Now I know why everyone was raving about the clang error-messages:
echo "void main() {}" > main.c
gcc -Wall -Werror --std=c99 main.c
main.c:1:6: error: return type of ‘main’ is not ‘int’ [-Werror=main]
cc1: all warnings being treated as errors
clang -Wall -Werror --std=c99 main.c
main.c:1:1: error: 'main' must return 'int'
void main() {}
^
1 error generated.
(not showing clangs pretty colours)http://i.imgur.com/BjWj7h6.png
FWIW, I have:
COLORTERM=gnome-terminal
TERM=screen
and Debian takes care of my termcap etc, afaik.http://i.imgur.com/0Hzze9G.png
Thats me on osx running tmux with TERM=xterm-256color.
C is insecure by design and IT is still paying for its widespread, when used by developers that don't use the best practices for secure C coding.
So when learning how to use it, the best way is to learn those best practices from day one.
Writing secure code is always harder than not, and developers love to take shortcuts.
For example, many of the IO functions like gets() are no longer valid in C11 exactly because how unsafe they are.
When you're writing the kind of software that's an invitation to hackers, like a web application, you should favor a language like PHP or Ruby, which takes things like buffer overflows out of the equation, and even then, you should know what you're doing.
Which if you follow my posts, you will see that I defend C and C++ should be replaced by safer systems programming languages, that exist since Modula-2 days.
Having said this, C and C++ are still used everywhere and will outlive most of us.
So when using them, for whatever reasons, at least one should take care to use the best practices regarding how to write secure and safe code in those languages.
No, Joe average user does not compile code.
-std=c99 -Wall -Wextra -Werror -pedantic-errorsAnyway, the hardest step for me in learning a language is when I take some running code and make one change to see what happens. Once I get in the swing of it, it gets much easier, but that first step is still hard to do.
Errors = safety nets are usually the main reason to make stiff learning curve. This would be a great help for them.
[1] mostly for maru, his lisp system, but even tty2html (ascii control -> html) is very clean and elegant.
Didn't someone win a IOCCC some years ago by providing an empty file that got compiled successfully?
There are a couple of great (free) resources on 32bit x86 assembly I'm aware of:
http://www.drpaulcarter.com/pcasm/ http://www.plantation-productions.com/Webster/HighLevelAsm/i...
There's apparently some plans on upgrading HLA to x86_64 -- I don't know of any good tutorials or guides on working on 64bit assembly specifically I'm afraid.
Just adding "-S" and looking at the source can be helpful of course, although I much prefer nasm/intel syntax, for clang/gcc that should require:
clang -S -mllvm --x86-asm-syntax=intel main.c
gcc -S -masm=intel main.c
Note that gas syntax is the "default" in the gnu-world, so it might be easier to just go with that if you're just starting out.It looks like clang might be generating less "noise" for tiny trivial programs, here's a side by-side-diff (in intel syntax) of int main{} vs int main { return 0;} (slightly reformatted):
diff --side-by-side main.s main.no-ret
.file "main.c" .file "main.c"
.text .text
.globl main .globl main
.align 16, 0x90 .align 16, 0x90
.type main,@function .type main,@function
main: # @main main: # @main
.cfi_startproc .cfi_startproc
# BB#0: # %entry # BB#0: # %entry
mov EAX, 0 mov EAX, 0
mov DWORD PTR [RSP - 4], 0 <
ret ret
.Ltmp0: .Ltmp0:
.size main, .Ltmp0-main .size main, .Ltmp0-main
.cfi_endproc .cfi_endproc
.section ".note.GNU-stack","",@progbits .section ".note.GNU-stack","",@progbits
It can be fun to do this with stuff like hello world (and contrast
puts("Hello, world!"); with printf("Hello world!\n);). http://c.learncodethehardway.org/book/http://stackoverflow.com/questions/2627511/why-do-c-compiler...
I'm not trying to nitpick but I'm worried newcomers to the language might be misled by your comments, the things you're talking about are not a concern for most coders unless they have to do things like low level embedded code, bootloaders and things like that. And then your entrypoint won't be "start" anyway, it'll be the reset vector or some lower stage jumping to a specific address for instance.
I'd better not mention the IOCCC then.