To become a good C programmer (2011)
fabiensanglard.net
fabiensanglard.net
It's pretty comprehensive, and I found the level was pretty good for a "not total newbie, but still not familiar with the subtilties" level that can be kind of hard to find resources for.
http://port70.net/~nsz/c/c11/n1570.html
http://port70.net/~nsz/c/c11/n1570.pdf
http://stackoverflow.com/questions/tagged/c
A good way to casually browse SO for interesting information is filtering by questions in the last <time period> and ordering by votes.
http://stackoverflow.com/search?tab=votes&q=%5bc%5d%20is%3aq...
[1] https://github.com/spc476/mod_blog
[3] https://github.com/spc476/CGILib
[4] gopher://gopher.conman.org/
The best part is that where stores his posts. SQL? Nope. NoSQL? Nope. Plain text files? Nope. Fucking LDAP. [1]
[1] Source: http://blog.fefe.de/?ts=a8d61c27
Can anyone name a language that they've grown to like more the more they learned about it? I would guess maybe only those in the LISP family would make the cut.
Other than things like signed integer weirdness, most complaints about 'C' revolve around the library. Well, don't use those parts of the library.
And eventually your fingers memorize all the nuanced and sure if you don't screw up it all works. But it's designed in a way where you end up shooting yourself in the foot. It's hard to reason about pointer and reference notations, everyone eventually miss a break in a switch - const is weird, arrays vs. pointers is weird. Symbols are needlessly overloaded to do different hings. Things that seems like they'd work for strange reasons don't EXAMPLE:
foo(const char p) { }
main(int argc, char argv) { foo(argv); }
I really really recommend opening up "Expert C Programming". I promise by page 50 you will be angry - not because there are so many gotchas, but because most of them are completely fixable. Just no one has bothered to do it
I guess it has problems with records, space leaks, and deployment to old machines. Maybe ML or F# are just as good for this purpose; I haven't really used them.
You're correct that a few of the Lisps have had this effect for me (Scheme, Common Lisp, EuLisp, Le-Lisp, elisp), but there have been a few dialects that I came to like less and less as I learned them (note that I do not necessarily dislike them, rather I'm disappointed by them): Clojure, Newlisp, and Racket, for example.
There are a few non-Lisps that I find myself liking more and more as I use them: Kitten and Mantra. They're both concatenative languages that take somewhat different approaches from the usual Forth-likes. I'm still not super proficient with them, though, so it's possible that the derivative of my fondness for them will invert yet. I've also had that experience with ksh (believe it or not) and Vim (a DSL for editing, if you will).
There have also been a few languages that have had a sort of "roller coaster" effect: at first they excited me greatly, then as I learned them better and better, I liked them more, then less, then more…. Some examples that come to mind are C#, Datalog, Haskell, Modula-3, OCaml, Prolog, Rust, and Standard ML.
Well, personally I've fallen in love with using FORTH for when I'm doing my hardware hacking (mostly on Arduino). I don't think that anybody would call it 'in the LISP family', but the language has similar grammar-extension capabilities, and I adore it for that.
Point here being that everyone's mileage will vary with dynamic and statically typed languages. But over time as the code base grows, the helpfulness of the language type becomes less (to the point of irrelevance). Instead the value of how cleanly the code has been written and maintained matters much more. Code with good tests, classes that are divided logically, well named methods and variables, etc, should be able to tell you what you are looking for regardless of language type.
Haskell
https://lkml.org/lkml/2015/9/3/428
(It's Torvalds on a bug made harder to spot by using array arguments in C, which you shouldn't do.)
g+ share: 0, reddit share: 1k.
.. so I guess it becomes clear why Google is deemphasising this.
No need for C and its flaws.
Learning C syntax is pretty easy. Learning to use the standard library is mostly a matter of reading man pages and other people's code. But I found understanding pointers and memory management completely opaque until I read that book. It definitely brought me from "beginning C hacker flailing about" to "intermediate C hacker flailing about in a more dangerous way".
Thoughts?
Or maybe it's better to say -- sanity checking on inputs is an (unmentioned) exercise left to the reader.
It won't cover C99, C11, or modern practices to mitigate buffer overflows. But it is still an excellent introduction to the fundamentals of C. It's also aimed at people who already know how to program in, say, Pascal, so is probably best not approached as a rank beginner.
The exercises in K&R are superb though and I highly recommend taking the time to do them all while you read K&R which I still feel you should, it is a small book so shouldn't take long to read.
well, there is a 'ModernC' book by Jens Gustedt of INRIA available here: http://icube-icps.unistra.fr/img_auth.php/d/db/ModernC.pdf
which might suit your fancy ?
Artificial example:
for( int i = 0 ; i < c+j ; i += b )
should be: for( int count = 0 ; count < sum+extra ; count += skip )
It may be allowed to use i in place of count here, but this is the only place where single name variables should be permitted and only if i is really just a simple array index iterator.all single letters = bad, java style thisIsALoopCounter = bad.
and in the c world i is almost universally understood to be used as a loop counter and index. If I came across 'count' in a c code I (briefly) might think it was related to a count of items in an array or similar.
https://github.com/jsoftware/jsource/blob/master/jsrc/cip.c
...just one of the many source files that make the interpreter for the J language.
Brilliant!
I doubt that this is either serious (unobfuscated) or handwritten code though.
I don't understand why 'i' has been given a pass. The argument boils down to saved keystrokes. Typing is not the bottleneck.
Because it is well enough established (in both programming and mathematics) that it communicates literally no less information to the reader than "iterator" or "index" would in the same context.
> The argument boils down to saved keystrokes.
Not at all. I, for one, find it easier to see the shape of the whole expression when the variable names are shorter.
But apart from that, I think using i,j,k as index variables in for-loop has become such a de-facto standard that I would only prefer long names such as "count" or "index" in situations where multiple indices may cause confusion. But then I'd probably use even more specific names than "count" or "index".
The reason is that in FORTRAN variables starting with i, j, k..n were defined as integers.
Back in the day I learned fortran first, then basic. People that learned basic first often would use the letter 'a' as a loop index instead of 'i'
Now days I still use 'i' but often use indx instead because my editor doesn't highlight single letter variables easily.
I have been using index instead of i in while loops lately. It's surprisingly concise.
sizeof( &array[0] )
This looks equal to: sizeof( array )
at first glance, which would give the size of the entire array in bytes, but of course the &array[0] expression is really: &*( array + 0 )
which simplifies to: array + 0
which is a pointer. And using sizeof on it gives the size of a pointer to int.Edit: (&* array) will also give a pointer.
---
This is just a really convoluted way to write 2:
&array[2] - &array[0]
&*(array+2) - &*(array+0)
(array+2) - (array+0)
2 - 0
Again I have never seen this written in such fashion.C89 3.3.3.4
"The sizeof operator... When applied to an operand that has array type, the result is the total number of bytes in the array."
C89 3.2.2.1
"Except when it is the operand of the sizeof operator or the unary & operator, or is a character string literal used to initialize an array of character type, or is a wide string literal used to initialize an array with element type compatible with wchar_t, an lvalue that has type ``array of type '' is converted to an expression that has type ``pointer to type '' that points to the initial member of the array object and is not an lvalue."
Additionally, here is a thread of Linus Torvalds pointing out even more of the confusing nature of arrays and sizeof in C:
I really like the idiom for passing sized arrays suggested at the end of that LKML thread[1]: pass them by reference!
void func(int (*arr)[256])
{
printf("arr size: %ld\n", sizeof(*arr));
}
int main(void)
{
int array[256];
func(&array);
}
[1] https://lkml.org/lkml/2015/9/7/147So your reasoning is not quite correct, it should really be that you think of
sizeof( &array[0] )
as being sizeof( &(something) )
where "something" could be of any type T, and so the '&' operator yields "pointer-to-T", to which sizeof will yield the size of a pointer.Another slightly confusing aspect is that `&array` gives you a "pointer to array" (which has the same value as `&array[0]`, but is of a different type). Most importantly, it behaves differently in pointer arithmetic (the implied offset is the size of the array, rather than the size of its elements).
&array[0] and array decay to the same thing, the pointer to the first element if they are used in an expression. But sizeof gives a different result, because array+0 'decays' to a pointer, and array doesn't.
[x] Strongly agree [ ] Agree [ ] Neutral [ ] Disagree [ ] Strongly disagree
For me, C, i.e., GCC, is most useful as a faster way to generate assembly for a particular CPU than typing it out from scratch. I use GCC as a code generator. I'd like to see more free asm code generators, but I am not holding my breath.
I do appreciate C as a medium for distributing reasonably efficient software.
1. Write some C
2. Dump the corresponding assembly code
3. Modify the code by hand
5. Load into assembly debugger
6. Learn
There is "C", the language, which can be relatively simple. Or hopelessly opaque depending on the author.
I think of C the language as just a shorthand for assembly. Only because that's how I use it.
http://www.lysator.liu.se/c/bwk-tutor.html
But then there is "C" in practice: the specifications, the "standard" libraries, preprocessors, Makefiles, autoconf, etc.
1. Program that reads some input (e.g., C language) and generates asm and/or opcodes.
2. Program that reads asm and/or opcodes and generates binary numbers ("object files").
No. 1 is what I need.
No. 2 is what I call an "assembler". Although terminology means less to me than what a program actually does.So, back in the day (and still for me, always):
assembler: ASCII source code in assembler language -- "which language did you code that in? - Assembler."
assembler: the integrated development environment (such as ASM-One) which produces executable machine code straight from source, with no linking step in-between; also known as a two-pass optimizing assembler.
No. 1 is a program that accepts input (e.g., RTL, MINIMAL, etc.) and generates asm.
I like to call this an asm code generator. Because today when people say "compiler" they are often referring to a collection of programs, some of which do not generate asm.
When I use that term I envision simple filters that take ASCII input, maybe even some sort of "template", and transform it into some other format that's useful. Ideally, asm. But not always.
For example, in GCC, for x86, there's a couple of programs that operate on i386-opc.tbl and i386-reg.tbl. I would not call them "code generators" but I suspect they are needed in order for "gcc -s" to work.
forget for the moment, that all of the old-guard-tech foundations is basically a castle made of glued together jello filled rubber ducky's. forget all the tricks needed to jump through that final hoop in assembly. forget even those hopeful endeavors of the languagewiser that stood up, and then came back because performance is a bitch and there use cases to edgy. forget all those library's that overpRomised, undereallocated and disspointered. forget all the futile attempts to steer this boat, carried on the hands of the likes of you, towards some sail-able waters. blissful unawareness settles in, while every "good c-programmer" near you starts to spit fire as soon as management declares a new megalomaniac project in C worthy the effort and thus starting. forget that strange feeling of elated Shame of being the best to repair the most broken car in town.
Then, and only then, you will be a "good" C-Programmer, one that knows all the tricks of trade, while not getting wiser.
(Yes, I'm in the dive in the deep end learning camp.)
Case in point: Star Control 2, a commercial title with a cult following, which had subsequently been open sourced, then modified to use SDL. Still works all the way from Windows through mobile phones to Solaris, thanks to portable C and the SDL library, and is an excellent game to boot. Original ran on DOS and the 3DO gaming console.
Microcontroller-C is extremely different from application-C but there are many less complicated concepts. Like never having to touch memory allocation or string munging.