[HN Gopher] Beej's Guide to C Programming [pdf]
___________________________________________________________________
Beej's Guide to C Programming [pdf]
Author : tumblewit
Score : 460 points
Date : 2021-04-23 05:56 UTC (17 hours ago)
(HTM) web link (beej.us)
(TXT) w3m dump (beej.us)
| dang wrote:
| It doesn't do the brisk business of the networking one, but there
| have been at least a couple past threads:
|
| _Beej 's Guide to C Programming_ -
| https://news.ycombinator.com/item?id=26100391 - Feb 2021 (1
| comment)
|
| _Beej 's Guide to C Programming (2007)_ -
| https://news.ycombinator.com/item?id=15198093 - Sept 2017 (79
| comments)
|
| As long as we're talking C programming, I'd single out this large
| thread with C Standards committee members from last year:
|
| _Tell HN: C Experts Panel - Ask us anything about C_ -
| https://news.ycombinator.com/item?id=22865357 - April 2020 (962
| comments)
| billfruit wrote:
| There was a "C Unleashed" book, a massive tome of 1000+ pages
| written by many famous programmers, many of them who where quite
| active in comp.lang.c, like Richard Heathfield and CB Falconer,
| had quite insightful material in it.
|
| Any one remember the heyday of comp.lang.c? I wonder what goes on
| in there now.
| [deleted]
| bluedino wrote:
| #c on EFnet!
| mistertester wrote:
| Yes, usenet was huge for me back in the early 90s when I had
| questions on C programming. I would ask them on
| comp.programming.c and had some of the best programmers
| providing guidance. Of course they were strict with
| questions/discussions being specific to ANSI C.
| ben_pfaff wrote:
| I wasn't sure anyone but the authors remembered C Unleashed! I
| wrote the chapter on binary search trees and balanced trees.
|
| Comp.lang.c was important to me for many years. I've met 5 or
| so of the regulars at least once. The most famous comp.lang.c
| regular is probably Tim Hockin of the Kubernetes project.
| beej71 wrote:
| Ben Pfaff... There's a name I recognize from back then. :-)
| jpcooper wrote:
| Is it beej or bj?
| beej71 wrote:
| One syllable, typically. But either works.
| billfruit wrote:
| Thanks very much! The code from the book proved very useful
| since C does not have a standard library of rich data
| structures.
| dmitryminkovsky wrote:
| There was a thread about that group a few months ago and this
| post in particular really stuck in my mind:
| https://news.ycombinator.com/item?id=26127632
| chubot wrote:
| That's what I remember from comp.lang.c -- lawyer-ly
| obsession with ANSI C, rather than C as it's being used. That
| is an important distinction which I respect, but they should
| have had some kind of sister forum that's more practical.
| They denied that hardware exists, etc.
|
| Also, obsession with ANSI C, analogous to obsession with
| POSIX shell, is sort of "middlebrow" in the sense that the
| people who WRITE the spec need to go outside of it to create
| a new version of it. Good specs are derived from real usage.
| [deleted]
| beej71 wrote:
| I bought that book ages ago. Good stuff. comp.lang.c still has
| a small group of knowledgeable regulars, but a lot of the "old
| guard" seems to have stepped away. And Usenet is a shadow of
| its former self, obviously.
|
| Reddit has more traffic nowadays.
| emilengler wrote:
| A thing I really enjoy about this guide is that it's close to
| common C paradigms and practices. Many guides lack this and only
| show outdated ones.
| [deleted]
| qwerty456127 wrote:
| Again, the string chapter is telling us about zero-terminated
| char arrays/pointers and doesn't even mention Unicode/UTF-8 or
| safety :-(
| beej71 wrote:
| I do have a chapter on Unicode and wide characters, but it's
| separate from the "classic" strings chapter. That said, I could
| certainly refer forward to it.
|
| And C11 only has minimal portable UTF-8 support, but I do talk
| about it. I think C21 will improve on that a bit.
|
| A note on safety would be well worth it. I'll do that. Good
| suggestion.
| rubicon33 wrote:
| I love Beej's guide to network programming. Back when I was just
| starting to learn to code, I wanted to get right down to the low
| level C stuff and his guide was what I used. It was simple and
| approachable and I had a running TCP client by the end of the
| day. It was a thrilling experience for a young novice.
| blunte wrote:
| IMO, pointers are less difficult to comprehend than other
| abstractions, like lambdas are.
|
| If you know how to walk down a street and stop at the right
| street number, then you have used pointers. And if you've ever
| observed that one tall building may "cover" a range of street
| numbers, such as 200-220, then you should understand how to move
| from one 4-byte "value" to the next in an array in memory.
|
| Anyway, many more analogies... probably better than this one.
|
| Maybe unions could make using pointers a bit more challenging,
| but again, tall buildings next to short buildings and so on. We
| do this kind of pointer calculation in real life.
| mumblemumble wrote:
| Pointers are like swazzles[1]. The construction is very simple.
| The principle behind how they work is very simple. Learning how
| to use one well enough that you can (a) consistently make it do
| what you want, and (b) not injure yourself in the process,
| though, is no mean feat.
|
| [1] https://www.atlasobscura.com/articles/swazzle-punch-and-
| judy
| cassepipe wrote:
| Pointers aren't that complicated but C syntax is misleading
| imho until someone comes along and tells you that the
| declaration syntax "follows use", which does not seem like the
| greatest idea. Then you get used to it and forget about it but
| when you don't know the principle behind declaration syntax, it
| does not help you reason about the language.
| young_unixer wrote:
| Yup. I spent a ton of time trying to make sense of pointer
| syntax (* operator/modifier), until I realized that it didn't
| really make sense (except for the simplest cases) and then I
| could get on my life.
| cassepipe wrote:
| There's actually a logic to it, although not an intuitive
| one at all, and it's that declaration should follow use.
| That is `int *ptr;` is a pointer to an int and to get the
| int you have to use * on it.
| jstimpfle wrote:
| The logic is that by declaring `int *ptr;` you
| effectively say that `*ptr` is an `int`. Only the first
| token (which must be a type) is syntactically special,
| the rest is normal expression syntax.
|
| Same goes for arrays, `int *x[30]` just says that
| `*x[30]` is an `int` (well, technically it's out of
| bounds by 1), thereby we're declaring an array of 30 int-
| pointers.
|
| Of course, that hasn't been entirely true since function
| declaration changed with ANSI C in the late 80s or so.
| kaba0 wrote:
| But int-pointer is the type of it. It makes no sense that
| it "sticks" to the variable name.
| bluetomcat wrote:
| There's a type and an identifier. In `int *pa[10]`, the
| identifier is `pa` and the type is `int *[10]`. A
| declaration simply specifies a name (the identifier),
| some operations around it (pointer dereferencing, array
| subscription, function calling, grouping parentheses) and
| the terminal type that you get after applying all those
| operators in the precise order as specified by operator
| precedence rules.
|
| When using that variable with the allowed operators, the
| resultant type of the expression is determined by the
| declaration: pa; // int *[10]
| pa[x]; // int * *pa[x]; // int
| kaba0 wrote:
| Thank you for the concise write up, but I think lowly of
| the [] syntax as well.
|
| And unary operators on an identifier are a different
| thing, though I similarly don't think adding one at the
| left, another at the right is a good thing. But I have
| trouble with the declaration site as well.
|
| It's getting out of reach of my knowledge, but I believe
| C's grammar being hacky is in part due to that as well.
|
| I didn't find exactly what I was looking for but here is
| some more on it:
| https://pdos.csail.mit.edu/archive/l/c/roskind.html
| cassepipe wrote:
| You missed the whole point. Yes, it makes no sense until
| you grok the logic of it and then it starts making sense
| (while still being unintuitive). Re-read the comments you
| are responding to.
| kaba0 wrote:
| Yeah I get that it has logic (though by being pedantic,
| anything we can write a parser for has logic, but I'm
| sure we could create some stupid languages), but as you
| yourself note, not very intuitive. And as far as I know,
| it doesn't ease the work of parser-writers.
| kevin_thibedeau wrote:
| int * a, b;
|
| Here it sticks to a.
|
| Then typedef comes along and ruins everything:
| typedef int * pint; pint c, d;
| Koshkin wrote:
| The reason the asterisk _naturally_ "sticks to" the name
| is simply the possibility to write a series of
| declarations like this: int a, *b,
| (*c)(int);
| kaba0 wrote:
| Which is a questionable saving of 2 lines and a few
| characters in a language where huge repetitions are a
| given, due to lack of templates/generics whatever.
| [deleted]
| chowells wrote:
| Well, you've demonstrated that memory addresses aren't that
| hard. But you've also demonstrated how easy it is to get
| undefined behavior in C programs.
|
| C's pointers aren't memory addresses. Ok, they tend to be
| represented as such at run time, but that's not what the spec
| actually says the are. And as far as compiler authors are
| concerned, they can do anything they want as long as it's
| within spec. Further, the spec even requires some additional
| behaviors pure memory addresses aren't capable of. See
| https://www.ralfj.de/blog/2020/12/14/provenance.html for
| examples of the extra requirements.
|
| Compared to that mess, lambdas are trivial. They're just
| functions.
| mytailorisrich wrote:
| C is an abstraction over assembly, really (benefits being that
| it is simpler by being more abstract and portable across CPU
| types).
|
| I've always thought that an introduction to CPUs (can take a
| simpler one as example) and how they work, how memory is
| (usually) organised, and to assembly would go a long way in
| helping understand many programming issues and C.
|
| My experience is that C or programming concepts are often
| taught in a very abstract/mathematical way, which can be hard
| to grasp compared to a more practical approach.
|
| If you take a concrete example where memory is effectively an
| array and indices are addresses (which holds true for most
| cases and, in any case is a good example) then understanding
| pointers becomes basically common sense and notations are
| simply conventions of the language you're using.
| Arch-TK wrote:
| Treating C as an abstraction over assembly is a surefire way
| to step into all the thousands of sharp edges C has. In fact
| I would hazard a guess that the majority of bugs found in
| software written in C are a result of programmers treating it
| as a portable assembler instead of a language for programming
| an abstract machine. So many incorrect assumptions arise as a
| result of telling people to treat C as a portable assembler
| that I think it's safe to call it an extremely bad bit of
| advice.
| mytailorisrich wrote:
| I was discussing pointers. I only commented in passing
| about C being portable over assembler. You could rephrase
| this as it being a language for programming an abstract
| machine and it would not change anything about my comment
| (nor would it change the fact that C is an abstraction over
| assembly)
|
| Thank you for your reply...
| jhgb wrote:
| > If you know how to walk down a street and stop at the right
| street number, then you have used pointers. And if you've ever
| observed that one tall building may "cover" a range of street
| numbers, such as 200-220
|
| I see that as a European, I have virtually no chance to
| understand pointers using street numbers. :)
|
| (Fortunately I've never had problems either with lambdas or
| with pointers.)
| atoav wrote:
| What pointers basically are is not particularly hard to grasp.
| What is harder to grasp it what can be done with them and how
| you can shoot yourself in the foot with them in non-obvious
| ways.
|
| I think I only understood much of it once I learned Rust,
| because you realize: _Ah, that thing I once did in C is
| something that maybe ahouldn 't be possible at all without
| extra steps_. Even if I were to nwver use Rust again, this
| definitly helped to understand how to use pointers more safely.
| chasil wrote:
| I think that pointers are a tool to control a CPU's indirect
| addressing modes from a higher-level language.
|
| Exposure to an assembler makes pointers easy to understand.
| ricardobayes wrote:
| Like my professor used to say, if you ever saw a pidgeon, you
| know what vectors are.
| augustk wrote:
| For anyone who wants to learn about pointers I can recommend
| studying a language simpler than C like for instance Oberon
| where pointers are more restricted. Having a look at Oberon can
| also broaden your view even if you know pointers in C.
| https://www.miasap.se/obnc/oberon-report.html
| http://people.inf.ethz.ch/wirth/Oberon/PIO.pdf
| Koshkin wrote:
| Actually, this could confuse things even more, because the C
| pointer and Oberon's POINTER TO have very little in common.
| qsort wrote:
| What's difficult to understand about pointers isn't the concept
| of a pointer itself, or even * and &, it's the fact that
| working with pointers requires you to simultaneously understand
| different abstraction levels. While it's not unique to
| pointers, and it's in fact the case for most nontrivial
| programming tasks, what's unique about C is that pointers are
| so pervasive you can't really do anything if you don't
| understand how to work with them.
|
| IME languages like Python aren't any easier than C to work with
| (ignoring UB issues of course), but it's certainly the case
| that you can probably kinda sorta get your job done with Python
| even without understanding the first thing of what you're
| doing, and that's not happening if you write in C.
| bluetomcat wrote:
| In C, pointers require you to think deeply about the
| ownership and lifetime of any "allocated object" at runtime.
| How long does it live, who is responsible for the
| deallocation, how many pointers does your program hold to
| that object (dangling issues). Ultimately, it can lead to a
| cleaner design if these issues are taken seriously up-front.
| jhgb wrote:
| > In C, pointers require you to think deeply about the
| ownership and lifetime of any "allocated object" at
| runtime.
|
| Unless you decide you use libgc, presumably?
| qsort wrote:
| I don't disagree with that, but most cases fall within a
| pretty clear pattern:
|
| - typedef struct { ... } foo
|
| - foo *foo_create()
|
| - void foo_destroy(foo *)
|
| - a bunch of functions that take foo* as their first arg
|
| which is kind of the same as a class and only more error-
| prone.
|
| I say this as someone who actually _likes_ C, but the
| manual memory management model is very often unnecessary,
| confusing, repetitive. There was an idea some time ago of a
| language extension that would extend the concept of
| automatic storage duration to allow an explicit destructor
| to be called when the variable goes out of scope, like
| <close> variables in some languages. I genuinely think
| things like that would make the language a bit more
| ergonomic without fundamentally changing its nature.
| AlbertoGP wrote:
| I'm actually implementing that right now for my own use,
| as a pre-processor.
|
| There is a much more advanced design and implementation
| at "A defer mechanism for C" (December 2020):
| https://gustedt.wordpress.com/2020/12/14/a-defer-
| mechanism-f...
|
| For my own purposes, I think I can live without handling
| stack unwinding so I continue working on my pre-
| processor.
|
| Since the pre-processor is not yet finished, there I use
| a vector1 of {.pointer, .destructor} where I put objects
| after initialization, with one macro at the end of each
| managed scope that calls the destructors for that scope
| in reverse order, then another macro meant for the
| function exit points that calls all the destructors in
| that vector. This has been built many times before by
| other people of course, it's just an exercise to see
| which difficulties arise.
|
| 1 Vector, growable array: I did my own trivial type-
| generic growable array, with the classic {.capacity,
| .len, .items}, but again there are many previous
| implementations. The two I've found more interesting are:
|
| - "C Template Library (CTL)":
| https://github.com/glouw/ctl
|
| - "Klib: a Generic Library in C":
| https://github.com/attractivechaos/klib/
| glouwbug wrote:
| With a bit of trickery CTL works much like the STL, in
| that containers can be built of containers:
| #define P #define T int #include <vec.h>
| #define T vec_int #include <deq.h>
|
| A deq_vec_int - analogous to std::deque<std::vector<int>>
| - is a neat example.
| tirrex wrote:
| For a vector alternative, I find this one easy to read
| and use :
|
| https://github.com/tezc/sc/tree/master/array
|
| It is just an array of your type, e.g int *numbers, so
| you have type info in debugger as well.
| cygx wrote:
| There's also a CTL fork that might be of interest:
| https://github.com/rurban/ctl
| alexhutcheson wrote:
| It's not standardized, but if you're using gcc, you can
| use the cleanup attribute for this:
| https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-
| Attribute...
|
| IIRC clang implements it as well, but I wasn't able to
| find a reference to it in their docs.
| Joker_vD wrote:
| Yeah, except when it doesn't follow the pattern: for
| example, there is no foo_destroy(), you're supposed to
| "just" call free() when you're done with it. Used to be
| very common (not sure how it is now), and very
| frustrating when you link against non-standard
| allocators.
| oscargrouch wrote:
| I also like the Ken Thompson extensions from which part
| of Go was inspired by struct X { int a;
| } struct Y { *X; int b; int c;} void
| add(Y* self, int number) { self->a += number;
| } Y y; y.a = 10; // composition
| y.add(1) // y.a = 11 now
|
| This alone would simplify C coding so much without taking
| any power out of it.
|
| The other extension i would add is some sort of interface
| or protocol.
|
| As soon as you can do something like "y.add(1)", having a
| generic contract to refer to things without having to
| know its concrete type is some of the good things from
| the OOP world.
|
| With this you would also be able to call some cleanup
| code and even a initializer.
|
| This is still C and its still much simpler than C++, and
| yet almost as powerful.
|
| C should propose these kind of things even if it was not
| that conservative and it would retain a lot of coders
| that migrate instead giving C barely evolved from its
| 70's roots.
| bluetomcat wrote:
| That's why I tend to always prefer automatic and static
| storage to dynamic allocation wherever possible,
| especially in cases where you don't have "N" items or "N"
| cannot possibly exceed a certain small value. Also,
| allocation/deallocation of the certain object need not be
| defined within its module. It should be up to the caller
| to decide whether to allocate the object on the stack,
| statically or dynamically depending on the caller's
| situation: foo f; foo_init(&f);
| foo_destroy(&f); ... foo *g =
| malloc(sizeof(foo)); foo_init(g);
| foo_destroy(g); free(g);
| unwind wrote:
| That is of course fine, with the drawback that it
| requires a public definition of the foo type.
|
| I would write the allocation as foo *
| const g = malloc(sizeof *g);
|
| to avoid repeating the type name and "lock" the
| allocation to the variable. If the type on the left hand
| side ever would change, this still does the right thing.
| quelsolaar wrote:
| Interesting, I tend to prefer a create and destroy
| function that allocates and frees the structure. That way
| you can have foo without it being initialized, and you
| cant have foo been freed without being de-initialized.
| Where do see the value in being able to move it between
| different memory types?
| TorKlingberg wrote:
| Coming from the embedded world, I am far more used to the
| style bluetomcat showed where the caller handles
| allocation. It takes more work to use, and you have to
| make sure to not use it before initializing or after
| destroying, as you said. The advantage is that the caller
| has full control of memory allocation. The object can be
| a local variable, a static, malloc:ed, come from a custom
| allocator (say a slab allocator), or be a part of a
| larger struct.
| quelsolaar wrote:
| That makes a lot of sense. I do some embedded
| development, but when I dont, I tend to prefer heap just
| because my memory debuggers are much more capable working
| with heap memory.
|
| In the case you show, foo would have to be a struct that
| doesn't contain pointers to additional allocated memory,
| but its a entirely valid use case and pattern.
|
| Calling malloc and free, has a cost associated with it,
| that the stack doesn't. But stack can in some cases, like
| with recursion be scary to use, because you dont know
| where it ends. If malloc returns NULL you know you have
| found the end and can do something reasonable.
|
| Thanks for you insight!
| dahart wrote:
| In games and embedded systems, a very common pattern is
| batched heap allocation: a single allocation of an array
| of foo, and/or an array of foo mixed with other types, or
| sometimes a memory managed data structure like a memory
| pool. This is one big reason that the C++ Standard
| Template Library was shunned in game studios for a long
| time; it automatically did it's own heap allocations,
| sometimes at inopportune times IIRC like in constructors,
| and didn't let the caller choose. EA wrote their own
| version (EASTL) that was game friendly because it allowed
| control of the allocator.
|
| In GPU programming, there are actual different memory
| sub-systems, with different sizes and different
| performance implications, so it's critical that the
| caller is able to do the allocation & deallocation any
| way they want. This is why most well designed GPU APIs
| rarely allocate GPU memory inside the API, but instead
| are designed to work with caller-provided pointers to
| buffers.
| krychu wrote:
| I always lacked a good discussion on the subject of
| allocation/deallocation strategies. Is there some
| recommended good read?
| bluedino wrote:
| People that can't comprehend arrays/lists in Python,
| especially multi-dimensional ones, would have had no chance
| in C
| unwind wrote:
| These are good points. I can sometimes feel that Python is
| more pointer-y (?) than people expect, with stuff like:
| a = {"one": 1, "two": 2 } b = a b["two"] = 99
| print(a["two"])
|
| The above prints 99, since "b = a" does not copy the value
| (the dictionary) but just the reference to the value ("the
| pointer", kind of). This is surprising to some people.
| qsort wrote:
| I agree, which is why I'm glad the first language I learned
| was C. I don't get to write a lot of C at work, but the
| concepts the language teaches you are the very fundamentals
| of programming.
|
| I know it's probably baseless, but I can't shake the
| feeling that people who learn modern languages before
| learning C are just making their own lives harder.
| bregma wrote:
| I think the same goes for learning assembly before
| learning C. A simple assembly-based computer [1] should
| be the first programming target in every "introduction to
| programming" class. After that, C becomes obvious and
| those who struggle with the fundamntals can be guided to
| more appropriate careers instead of dumbing down the
| tools everyone uses.
|
| [0] https://www.instructables.com/CARDIAC-CARDboard-
| Illustrative...
| skocznymroczny wrote:
| Reminds me of the Python trap that I fall into every few
| months because I forget about it:
|
| def foo(mylist=[]): mylist.append("a") return mylist
|
| mylist is only initialized once, so the function will
| actually return one more "a" with each function execution
| ryl00 wrote:
| This is one part (of many) of perl that I like, that it
| exposes the pointer-y parts to the programmer (to abuse :))
| # hash my %a = ( 'one' => 1, 'two' => 2 );
| my %b = %a; $b{ 'two' } = 99; #
| prints 2 print $a{ 'two' }, "\n"; #
| reference to hash my $a = { 'one' => 1, 'two' => 2
| }; my $b = $a; $b->{ 'two' } = 99;
| # prints 99 print $a->{ 'two' }, "\n";
| deckard1 wrote:
| The real difference is Perl has typed variables, such as
| hashes or arrays, which other languages typically do not.
| Which does make it convenient when you need to clone the
| object, such as "%b = %a" example. Perl borrows the sigil
| concept from Bash and other shells (which makes sense,
| given the historical context of Perl). The only other
| language I know of that uses sigils in such manner is
| BASIC. Other languages, such as Ruby or Common Lisp, use
| them as syntactic convention rather than as a feature
| that the compiler/interpreter understands.[1]
|
| Most dynamic languages expose the data as references. In
| fact, the one thing that trips up JavaScript developers (
| _especially_ in React) is that they do not understand how
| references work. I see senior and lead developers
| inadvertently doing mutation all the time. Or getting
| incredibly paranoid that two identical strings, for
| example, do not equal each other in the strictest sense
| in JS. They also throw in memoization everywhere due to
| their fundamental lack of understanding.
|
| You can always tell the developers that do not have
| C/C++/Pascal experience.
|
| [1] https://en.wikipedia.org/wiki/Sigil_(computer_program
| ming)
| serial_dev wrote:
| It's also similar in Java's pass-by-value vs pass-by-
| reference (pass as well as copy), if I recall correctly.
| kaba0 wrote:
| Actually, most languages only have pass-by-value, being
| "pedantic" (but it is actually a useful distinction). I'm
| sure there are other's but out of the majorly used
| languages, only C++ has actual references. Pointers are
| passed by value, that is the pointer value gets copied.
| References are a language level construct.
|
| Here is a great "rant" at it in case of Java:
|
| http://www.javadude.com/articles/passbyvalue.htm
| ZoomZoomZoom wrote:
| Pointers seem easy until you understand the pointers you're
| working with do not correspond with the basic hardware model
| you have in mind:
|
| https://www.ralfj.de/blog/2018/07/24/pointers-and-bytes.html
|
| https://www.ralfj.de/blog/2020/12/14/provenance.html
|
| https://www.ralfj.de/blog/2019/07/14/uninit.html
| dimran wrote:
| This is a wonderful book if you want to understand how the OSI
| model of internet works, clearly illustrated network apis. Man
| this book was amazing.
| cpach wrote:
| I think you're confusing it with another book. This is a guide
| to C programming. You're probably thinking of _Beej 's Guide to
| Network Programming_ :)
|
| https://beej.us/guide/bgnet/
| signa11 wrote:
| Jens Gustedt's "Modern C" (https://modernc.gforge.inria.fr) is an
| _excellent_ resource as well.
| k_sze wrote:
| Jens Gustedt is a co-editor of the ISO C standard, so he knows
| his shit. Modern C is probably the best book about modern C,
| short of reading the standard.
| SAI_Peregrinus wrote:
| It's far easier to read than the standard, too, since it's
| explanatory rather than declaratory. The standard tells you
| _what_ C can do, Modern C teaches you _how_.
| gnuvince wrote:
| What does "modern" C imply? AFAIK, there are not very many new
| language features; is it about organizing code differently than
| what one would learn from K&R?
| beej71 wrote:
| I'm chuckling to myself at "there are not many new language
| features" because that's what I thought.
|
| There's fair amount added to the core since C89, actually...
| And if you include the library changes, game over! I had no
| idea how much had been added.
|
| More challenging is to find what's been subtracted.
|
| This no longer defaults to int:
|
| static i;
|
| And gets() is toast.
|
| Anyone know any others?
| JoeAltmaier wrote:
| Array initializers! Lots of changes there. Oh, things
| subtracted? Wasn't there a change in typedef vs type tags?
| ashconnor wrote:
| C99 I would imagine: https://en.wikipedia.org/wiki/C99
| unwind wrote:
| The current standard is C17, of course:
| https://en.m.wikipedia.org/wiki/C17_(C_standard_revision).
| thamer wrote:
| Apart from the new features added in C11 or C17 that others
| have mentioned, both Beej's Guide and Modern C also cover
| threads and string encoding (neither of these topics are
| covered in K&R 2nd edition, as far as I remember). Beej's
| Guide also has a section on internationalization and one
| about date/time handling.
|
| But yes, the code is also quite different than in K&R which
| is relatively terse. See for example this comment in K&R
| about strcpy on print page 105 (page 119 of the PDF)[1],
| where after showing two versions of strcpy that are pretty
| readable and easy to follow, the book says:
|
| > In practice, strcpy would not be written as we showed it
| above. Experienced C programmers would prefer
| void strcpy(char *s, char *t) { while
| ((*s++ = *t++) != '\0') ; }
|
| Followed by a paragraph saying the condition could be
| simplified, and that
|
| > the function would likely be written as
| void strcpy(char *s, char *t) { while
| (*s++ = *t++) ; }
|
| Make of that what you will :-)
|
| [1] https://kremlin.cc/k&r.pdf#page=119
| mumblemumble wrote:
| According to the introduction of the book, C17. Which is
| mostly just bugfixes on C11. But, compared to c99, you get
| nice things like generic expressions, better unicode, and
| (standard) multithreading.
| wott wrote:
| > _But, compared to c99, you get nice things like generic
| expressions_
|
| I'd have a hard time calling the way they designed _Generic
| "a nice thing" :-)
| potbelly83 wrote:
| Nice book. As a C++ programmer how much of its discussion
| related to C's storage/memory model would carry over to C++?
| fctorial wrote:
| All of it. C++ is a superset of C.
| GeorgeTirebiter wrote:
| Others disagree: https://mcla.ug/blog/cpp-is-not-a-
| superset-of-c.html
| Arch-TK wrote:
| You don't really have to ask others. The C and C++
| standard disagree, you can easily find instances of this
| disagreement if you just peruse them. The easiest example
| to find is the difference in behavior of the auto keyword
| or in how conversions from void * to something_else * are
| implicit in C not in C++. There's now also an extreme
| number of subtleties in terms of undefined behavior which
| differ between the languages.
| varajelle wrote:
| And even if it was, the idioms would still be different.
| Even if yaml is a superset of JSON, you wouldn't apply
| JSON pattern (eg. Using a "_comment" key for comments) to
| yaml. And similarly, many of the JavaScript design
| pattern won't apply to typescript because it has language
| features instead of conventions.
| vram22 wrote:
| Bjarne Stroustrup, C++ creator, disagrees, IIRC. Think I
| read it on his site.
|
| Edit:
|
| https://www.stroustrup.com/bs_faq.html#C-is-subset
|
| >Please note that "C" in the paragraphs above refers to
| Classic C and C89. C++ is not a descendant of C99; C++
| and C99 are siblings.
| aphrax wrote:
| I've enjoyed this guide a number of times but each time I hit a
| brick wall trying to understand pointers. I'm still keen to learn
| but it just doesnt 'click' for me...
|
| Edit: poor grammar
| DyslexicAtheist wrote:
| around 25 years ago I got so frustrated because I hit the same
| brick walls over and over especially with advanced pointer
| stuff. It sounds silly today but what helped me are some really
| basic books about C. iirc the "for dummies" series and others.
|
| It took another couple of years until I understood what I
| lacked wasn't time spent reading another section on pointers
| but additional tooling. Using a debugger and stepping through
| programs was the next breakthrough.
|
| Looking back today understanding my C (on UNIX) isn't just the
| language it's a whole ecosystem of tools to measure what is
| going on and manipulating state so that I can troubleshoot.
| After gdb came valgrind, strace, lsof, signal handling (kill),
| process control, gcov, the appropriate type of CFLAGS to use
| (e.g. the compiler itself) and how to stay sane using Make.
|
| None of them have to do with pointers but they make life a lot
| easier. To become productive at this takes years but becoming
| good took me decades. C (imho) isn't just another language but
| a complete career path with dozens of branches into other
| areas.
|
| If you stay patient with yourself and treat it as a journey
| instead of a milestone it can deepen your understanding of
| systems (nod to eBPF) in situations many others will bail out
| long before.
|
| Don't give up and then not much will look scary any more.
| agumonkey wrote:
| Ability to inspect is vital indeed
| aphrax wrote:
| Thanks so much for this reply, really quite inspiring. Much
| appreciated.
| Koshkin wrote:
| 1) A pointer is a memory address of an object.
|
| 2) Pointer arithmetic takes into account the size of the type
| pointed to.
|
| 3) The asterisk operator gives you access to the object.
|
| 4) The ampersand operator gives you the pointer to the object.
|
| If you understand this, you understand pointers. (The arrow
| operator is syntactic sugar.)
| sanedigital wrote:
| One analogy I've used to teach pointers is to think of them as
| phone numbers. They're an identifier used to get ahold of
| something that you might not otherwise know exactly where it
| is. If you call my number, I'll pick up. But if I transfer my
| number to someone else, that doesn't mean anything happened to
| me personally. That number is just not pointing to new anymore.
| unwind wrote:
| That is fascinating, thanks for sharing. What part of pointers
| is it that makes it so hard for you to grasp, if you have any
| thoughts?
|
| Do you have any experience in other programming languages? How
| familiar are you with low-level computer architecture, at the
| CPU/memory level?
|
| I guess one important part is to realize that in C, variables
| are basically names for memory locations, that in turn hold
| values. In other languages variables can be more abstract, and
| you have no idea how the value(s) are being associated with the
| variable name.
|
| I started writing an example here, but I ran out of time and it
| wasn't good enough. :) Sorry.
|
| EDIT: Now I've taken a loo at the relevant pages in the guide
| itself, and it seemed to explain the concepts very clearly and
| easily, so ... I'm not sure how to help. :)
| aphrax wrote:
| Thanks for this - I think you are on to something when you
| mention the low level architecture, on reflection this is
| where I need to fully understand the concepts - I'm messing
| around in this area with the usual (Nand to Tetris) type
| info/tutorials. I'll then come back to this manual I'm sure.
| Like I say - I've enjoyed it quite a bit. Its certainly me
| lacking - not the book!
| dave84 wrote:
| One tool I use with my own students to visually demonstrate
| C pointer code is CTutor from PythonTutor.
|
| http://pythontutor.com/c.html#mode=edit
|
| If you click down to the bottom and choose from the
| examples "Pointer Levels" you'll get a good idea of the
| tools powers.
| argvargc wrote:
| Something that might help is understanding a very
| fundamental thing about computers: they are very, very
| stupid.
|
| Essentially, they don't/can't know anything about anything,
| at the most fundamental levels of their construction, and
| have to be hand-held every tiny step of the way.
|
| A computer is essentially a highly complex arrangement of
| on/off switches - there's little else fundamentally in
| there doing anything at all other than something causing
| the first switch to cycle between on and off states and
| cascade to all the rest (this isn't entirely accurate but
| it's close enough to make te point).
|
| This gives rise to situations where in order to create
| greater levels of complexity, lots of unintuitive, and
| seemingly even pointless things need to be done. For
| example: assigning letterbox addresses to every discrete
| portion of memory. Then things like "I want to read the
| values from this part of memory up to this part" require
| laboriously adding 1 to a value (a pointer) that tracks
| which address the computer is currently "thinking" about.
| It's so stupid it needs to remember where it is all the
| time like this, or it can't do anything.
|
| Because C is very close to this mundane and laborious
| fundamental architecture, it (usefully in that case) deals
| with concepts like "pointers".
|
| In languages at just a bit higher level, the language
| internals deal with pointers so that we as programmers
| don't have to.
| sedeki wrote:
| Try to explain where you're stuck.
| redis_mlc wrote:
| Just learn C by reading and working through the K&R book. (It's
| one of the best CS books ever written.)
|
| https://www.amazon.com/Programming-Language-2nd-Brian-Kernig...
|
| Also, there's nothing magical about pointers - scripting
| languages use "handles", which is the same thing except they're
| read-only to the end-user programmer.
|
| The real challenge with C is multi-threaded programming, so
| don't do that if you don't need it.
| dvfjsdhgfv wrote:
| > Just learn C by reading and working through the K&R book.
| (It's one of the best CS books ever written.)
|
| This is really an amazing feat: books on programming
| languages age really fast. This one - not so much. And you
| can really appreciate the careful thought that was put in
| each sentence. Peerless.
|
| > The real challenge with C is multi-threaded programming, so
| don't do that if you don't need it.
|
| Well, these days it's harder and harder to avoid it if you
| want to write efficient apps - we got more cores and the
| clocks remain more or less the same.
| redis_mlc wrote:
| > Well, these days it's harder and harder to avoid it if
| you want to write efficient apps - we got more cores and
| the clocks remain more or less the same.
|
| There was some article a few years ago that said the apps
| they looked at didn't actually run faster after making some
| routines parallel, so it depends, and you will definitely
| have more debugging to do.
| beej71 wrote:
| I agree. If you're only going to read one book, that's the
| book. :-)
| cassepipe wrote:
| Personnally I have learned C following the CS50 course on
| Harvard's youtube channel and pointer came easily with
| http://alumni.cs.ucr.edu/~pdiloren/C++_Pointers/.
|
| It's a great (free as in beer) start.
| squarefoot wrote:
| Pointers are easy and fun, just keep experimenting with them.
| What is essential is understanding that they're nothing more
| than like a piece of paper containing _where_ something is
| instead of being part of that something, and they 're the same
| size of the address registers of the underlying hardware as
| they must be able to point everywhere in the addressable
| memory. Therefore, on a 32 bit system pointers will be 32 bits
| long, on a 64 bit system they will be 64 bits long, etc. no
| matter what they point to.
|
| That is, both a pointer to a single byte and a pointer to a
| 10GB memory chunk will be of the same size because they just
| hold a memory location whose value represents where that data
| starts. Therefore, declaring pointers _to_ a certain type doesn
| 't change their size at all, it just becomes handy when one
| needs to go back and forth in a memory area in which objects of
| that type are stored one after another, so that incrementing or
| decrementing the pointer by a number actually means that number
| times the size of the objects. Imagine asking for directions to
| someone and he replies "3rd door" or "3rd building" or "3rd
| block"; he gave you a pointer that is always the same size, but
| how much you have to walk will depend on the destination
| (size).
|
| Once grasped the above, it should become a lot more easy; I had
| the same problems, then one day had a flash and they became
| totally clear (and fun).
|
| It may be of help experimenting with a debugger, or simply
| printf-ing all values a pointer assumes when declared,
| assigned, incremented/decremented etc. Keep also track of the
| pointed data values, changing it instead of the pointer, or the
| other way around, are common mistakes.
|
| An old small command line program like "cdecl" can help a lot
| to understand complex declarations, and someone has even made
| an interactive webpage around it (cdecl.org).
|
| example:
|
| cdecl> explain char ( _(_ x())[]) () declare x as function
| returning pointer to array of pointer to function returning
| char
| bluetomcat wrote:
| Just another integral data type which supports not only
| arithmetic (adding or removing an integral value), but also
| "dereferencing" which means getting a value of the pointed-to
| type at the pointed-to address.
|
| The quantities added or removed in arithmetic operations are
| the same as the size of the type that is being pointed to.
| shric wrote:
| It's incorrect to call a pointer an integral type. It doesn't
| behave like an integer (you can't add two pointers together).
| You can't even subtract two pointers from each other unless
| they point into the same array (or one element past) without
| causing undefined behaviour. You can't even reliably convert
| a pointer generally to an integer and back again unless it's
| a void *.
|
| Edit: just remembered I wrote a rambling on this in 2014:
| https://ramblings.implicit.net/c/2014/04/21/pointers-are-
| not...
| bluetomcat wrote:
| Strictly it's not an integral type as you point out, but
| for the purpose of introducing a beginner who might be
| afraid that there is "deep magic" involved, it can be a
| helpful comparison.
|
| Subtracting two pointers yields ptrdiff_t which is not a
| pointer type in itself.
| shric wrote:
| Pretending it's an integral type leads to all sorts of
| conceptual mistakes, imho. It has almost no comparable
| semantics to integers.
| 1_player wrote:
| A pointer is a level of indirection.
|
| A regular variable is a place in RAM that contains a certain
| value.
|
| A pointer is a variable whose value is the address of another
| variable.
|
| X = 5
|
| Y = location in memory of X
|
| Now you can use Y to manipulate X
| quelsolaar wrote:
| Try watching this: https://youtu.be/443UNeGrFoM
|
| Its long and is filled with other stuff about C programming but
| it goes in to dept about how to think about pointers. Good
| Luck!
| throws23577 wrote:
| I haven't read these 2 books, but would like the opinion of
| someone who did.
|
| [1] C Interfaces and Implementations: Techniques for Creating
| Reusable Software by David Hanson - HN's tptacek seemed to rave
| about this book, that's how I heard of it. Wonder what he thinks
| of it in 2021.
|
| [2] C Programming: A Modern Approach by K. N. King - this one
| seems to be loved by many. Seems to be more 'beginner-friendly'
| than the 1st one I guess.
| ZoomZoomZoom wrote:
| You can always check reviews published by ACCU.org:
|
| K. N. King "C Programming":
|
| https://accu.org/bookreviews/1999/graham_1260/
|
| Ben Klemens "21st Century C":
|
| https://accu.org/bookreviews/2016/demin_1882/
|
| Robert C. Seacord "Effective C":
|
| https://accu.org/bookreviews/2020/glassborow_1952/
|
| https://accu.org/bookreviews/2021/bruntlett_1959/
| throws23577 wrote:
| Wow I never heard of Robert Seacord's 'effective C'. Thank
| you.
|
| Edit: Here's a short rationale for the book by the author.
|
| https://ieeexplore.ieee.org/document/9237323
| exceltior wrote:
| Thanks for sharing this
| enahs-sf wrote:
| I love C programming. Even though people say it's dangerous and
| easy to shoot yourself in the foot, It really is the simplest and
| most elegant way forward. That said, having to invent the wheel
| yourself so much, it is not as time efficient as some more modern
| languages.
|
| I liken it to an artisanal craftsman's tool versus a modern
| multi-tool like a dremel which would be something like python.
| seibelj wrote:
| Totally agree - sometimes I solve small problems in C rather
| than a scripting language. It feels like freedom and the result
| is so damn fast.
| DyslexicAtheist wrote:
| it actually has working examples for all of the C library calls
| even math routines. Not sure if it's complete but it seems so.
| This seriously helps bridging the gap between man (2) pages and
| putting things into working code and only beef I have is that I
| didn't have it 25 years ago. Very cool.
| saagarjha wrote:
| Nit: most of the C library calls are in section 3; section 2 is
| system calls.
| DyslexicAtheist wrote:
| yepp (me facepalm)
| beej71 wrote:
| It's not complete... There are tons of functions in C11+. I'm
| whittling it away.
|
| Putting in the examples for all the calls--I stole that idea
| from The Turbo C Bible, a book I really loved back in the
| day... because of the examples.
| transient_47 wrote:
| I stumbled upon this gem a while ago [0] while looking for a
| decent tutorial and reference to C:
|
| _Stuff that should be avoided: [...]
|
| Beej's Guide to C:
| http://beej.us/guide/bgc/output/html/singlepage/bgc.html
|
| Full of mistakes.
|
| [...]_
|
| Could someone confirm this? I've seen a lot of threads here on HN
| praising beej's guides so I am somewhat confused.
|
| [0] http://www.iso-9899.info/wiki/Main_Page
|
| edit: Formatting
| tom_mellior wrote:
| On a quick skim of some introductory parts I found:
|
| > When you have a variable in C, the value of that variable is
| in memory somewhere, at some address. Of course. After all,
| where else would it be?
|
| It would be in a register. Of course. Or it would be eliminated
| by a compiler optimization. Of course.
|
| Same error later on:
|
| > When you pass a value to a function,a copy of that value gets
| made in this magical mystery world known as the stack
|
| No. In most common cases, arguments will not be passed via the
| stack. This goes on to clarify in a footnote that the
| implementation might not actually use a stack, and that the
| stack has something to do with recursion. That part is true,
| but the values saved on the stack for recursing are not the
| same as function arguments.
|
| Neither in the Variadic Functions chapter nor anywhere else are
| the default argument promotions mentioned -- this will bite
| someone who tries to write a variadic function that gets floats
| out of the variadic argument list, which you cannot do, since
| passing a float to a variadic function promotes it to double.
|
| Speaking of floats... This is one of those tutorials that are
| very confused regarding their target audience. For example, in
| the "Variables" section it goes out of its way to define: "A
| "byte" is an 8-bit binary number. Think of it as an integer
| that can only hold the values from 0 to 255, inclusive." (which
| isn't the C definition, but this _really_ is nit-picking) but
| then happily goes on to talk about Booleans and floats without
| explaining what _those_ are. What reader has a background that
| would make this useful?
|
| Overall, from the little I've seen, I'd give this an initial
| rating of "broadly correct but with definite mistakes".
|
| Even if it were fully correct, I dislike the verbose style, and
| I wouldn't recommend this tutorial. For example, in the Hello
| World chapter, we have the following "explanation" of the line
| "#include <stdio.h>":
|
| > Now, what is this#include? GROSS! Well, it tells the C
| Preprocessor to pull the contents of another fileand insert it
| into the code rightthere.Wait--what's a C Preprocessor? Good
| question. There are two stages (well, technically there are
| more thantwo, but hey, let's pretend there are two and have a
| good laugh) to compilation: the preprocessor and thecompiler.
| Anything that starts with pound sign, or "octothorpe", (#) is
| something the preprocessor operateson before the compiler even
| gets started. Commonpreprocessor directives, as they're called,
| are#includeand#define. More on that later.Before we go on, why
| would I even begin to bother pointing out that a pound sign is
| called an octothorpe?The answer is simple: I think the word
| octothorpe is so excellently funny, I have to gratuitously
| spread itsname around whenever I get the opportunity.
| Octothorpe. Octothorpe, octothorpe, octothorpe.Soanyway. After
| the C preprocessor has finished preprocessing everything, the
| results are ready for thecompiler to take them and
| produceassembly code8,machine code9, or whatever it's about to
| do. Don't worryabout the technical details of compilation for
| now; just know that your source runs through the
| preprocessor,then the output of that runs through the compiler,
| then that produces an executable for you to run.
| Octothorpe.What about the rest of the line? What's<stdio.h>?
| That is what is known as aheader file. It's the dot-hat the end
| that gives it away. In fact it's the "Standard I/O" (stdio)
| header file that you will grow to knowand love. It contains
| preprocessor directives and function prototypes (more on that
| later) for common inputand output needs. For our demo program,
| we're outputting the string "Hello, World!", so we in
| particularneed the function prototype for theprintf()function
| from this header file. Basically, if we tried to
| useprintf()without#include <stdio.h>, the compiler would have
| complained to us about it.How did I know I needed to#include
| <stdio.h>forprintf()? Answer: it's in the documentation.
| Ifyou're on a Unix system,man printfand it'll tell you right at
| the top of the man page what header files are required. Or see
| the reference section in this book.:-)Holy moly. That was all
| to cover the first line! But, let's face it, it has been
| completely dissected. No mysteryshall remain!
|
| Only one sentence of this is relevant for an introductory Hello
| World chapter: "Basically, if we tried to use printf() without
| #include <stdio.h>, the compiler would have complained to us
| about it." None of the rest is relevant or helpful to a
| beginner who is just seeing their first ever C program. Also
| "completely dissected" isn't true either; there is a lot more
| to be said about headers.
| beej71 wrote:
| It's a tough line between intro and The Rabbit Hole. But I'll
| see what I can do there.
|
| Appreciate the feedback. Some good suggestions here that I'll
| add.
| fps_doug wrote:
| > It would be in a register. Of course. Or it would be
| eliminated by a compiler optimization. Of course.
|
| Since you mention relevance for beginners later on in your
| post I'd argue this isn't relevant either. This concept holds
| true for simple code that doesn't do advanced stuff like
| working with hardware. As soon as you do &variable, you get
| an address and can work with it. If the compiler optimized
| something away you never use you might as well just pretend
| it's in memory somewhere for the sake of a mental model
| that's easy to grasp. Same with passing variables via stack.
| A simple compiler could do it just like that.
|
| That isn't to say the tutorial is good/not good, but these
| points in particular seem rather sane to me. Far from
| "Mastering C Pointers" at least :)
| tom_mellior wrote:
| > Since you mention relevance for beginners later on in
| your post I'd argue this isn't relevant either.
|
| Agreed. At the time that variables are introduced, it
| should just say "a variable is a name for a location where
| a value is stored". I didn't mean to suggest that the
| tutorial should go into needless detail at that point. Just
| that the needless detail that it currently goes into is
| wrong.
|
| > Same with passing variables via stack.
|
| Again, my problem is just with the needless detail. When
| you pass a value it is copied (that is the relevant part)
| somewhere where the callee can find it (that somewhere is
| the irrelevant part).
| Twisell wrote:
| > Only one sentence of this is relevant for an introductory
| Hello World chapter: "Basically, if we tried to use printf()
| without #include <stdio.h>, the compiler would have
| complained to us about it."
|
| Quite the contrary in my opinion. As a beginner I was very
| frustrated with most approach that say "Just put that thing
| that is needed and will be explained latter. And it work good
| job attaboy!"
|
| And maybe 250 pages latter if the author didn't forgot in the
| meantime you get a one liner mention that link back to the
| first introduction of the syntax.
|
| At least this guide don't let the reader in the fog
| wondering.
| Const-me wrote:
| > It would be in a register. Of course. Or it would be
| eliminated by a compiler optimization
|
| As long as you're taking, and using, the address of that
| variable, it's almost guaranteed to be in memory. Even if it
| won't, the compiler guarantees the output of the program will
| be equivalent to unoptimized code.
|
| > arguments will not be passed via the stack
|
| I'm not sure explaining nuances of various calling
| conventions, and how they differ across processors and OSes,
| is useful information in a document about C and targeted
| towards beginners.
|
| You're talking about things which are underneath C in the
| abstraction layer hierarchy. The abstraction has many layers,
| the lowest one being quantum physics. One has to stop
| somewhere, and this article decided to stop at C, as opposed
| to assembly.
| tom_mellior wrote:
| See my reply to your sibling comment. I wasn't proposing
| adding more irrelevant detail. If anything, I was proposing
| removing the existing irrelevant and incorrect/very
| incomplete detail.
| thrwaeasddsaf wrote:
| > One has to stop somewhere, and this article decided to
| stop at C, as opposed to assembly.
|
| As soon as you mention the stack, you've gone beyond C and
| started talking about something that is not C.
| [deleted]
| determinateproc wrote:
| Beej himself lists this as an 'alpha-quality document' on the
| download page [0] and if I remember correctly, it has been so
| for years. Wonder why this is posted here on HN.
|
| [0]: http://www.beej.us/guide/bgc/
| petee wrote:
| I think posts like this are handy just for the extra exposure
| an alpha document might need; there's a lot of good feedback
| and discussion here that hopefully beej comes across someday
| and can finish the book
| determinateproc wrote:
| On further observation the git repository of the book [0]
| seems to be quite active. Maybe this book might be finished
| after all.
|
| [0]: https://github.com/beejjorgensen/bgc
| beej71 wrote:
| Backstory: I started writing this book for novice
| programmers about 15 years ago. It was going to be a lot
| shorter.
|
| But I became disinterested because:
|
| 1. Most beginning programmers don't start with C
|
| 2. I wouldn't get a chance to go deep and explore the
| language.
|
| So I shelved it, unfinished.
|
| Flash forward to about a year ago... I had flash of
| inspiration: change the audience to intermediate
| programmers.
|
| Now I could skim the general conceptual stuff and get
| into more details.
|
| One thing, though. C actually added a _lot_ of stuff in
| the intervening years. I didn 't realize the magnitude of
| the project.
|
| Oh well! Too late to turn back now!
| fctorial wrote:
| > Most beginning programmers don't start with C
|
| Except literally every indian engineer. They teach C to
| mechanical and chemical engineers for some reason. (It's
| not an elective)
| unfocused wrote:
| Just wanted to say THANK YOU as I read your guide to
| network programming way back in 2000, over 20 years ago!
| I was just starting out in C network programming on
| VxWorks :) Glad to see you're still updating your guides.
| beej71 wrote:
| Thanks! Makes my day to hear people find the work useful.
| :)
| beej71 wrote:
| I recently overhauled it in a big way.. er, "am overhauling
| it".
|
| And I'm sure it's full of mistakes. It's over 500 pages, most
| of which has yet to be edited, so if there are fewer than
| 1000 defects, I'd be shocked.
|
| But I fix them all as I find them, or as they're pointed out.
| And after an eventual editing pass, things will be better.
|
| And if it's not useful to someone, I take no offense I'd they
| don't like it. :-)
| yrgulation wrote:
| I commented this before on a previous post on one of beej's
| guides: https://news.ycombinator.com/item?id=26100075
|
| These tutorials are the gold standard of tutorials. I wish more
| content would be as straight to the point and easy to follow.
| mnunez wrote:
| Just found out that it has an actively maintained GitHub
| repository, with 35 or more commits this April alone.
| https://github.com/beejjorgensen/bgc/commits/main
| Spivak wrote:
| Is there any guide that operates at the level of the C abstract
| machine and a real platform because it's always really jarring to
| have lots of hand-wavy statements like
|
| > When compiling C,machine codeis generated. This is the 1s and
| 0s that can be executed directly by the CPU.
|
| No! Tell me about how the code is translated into an ELF
| executable, linked, has its memory laid out by the OS and then
| executed.
|
| > I'm seriously oversimplifying how modern memory works, here.
| But the mental model works, so please forgive me
|
| No! Tell me about how memory works in the C abstract machine
| which is what you can actually program against and guaranteed by
| the compiler.
|
| > Nothing of yours gets called before main(). In the case of our
| example, this works fine since all we want to do is print a line
| and exit
|
| No! tell that main is special because it's mapped to the _start
| symbol or at least eventually jumped into by code at that symbol
| which has an address that's stored by the linker in e_entry.
|
| Like I might be the weird one but this kind of writing (which is
| common to seemingly all C texts) confuses me more than if it had
| just been explained.
| caseyavila wrote:
| > It's especially insidious because once you grok pointers,
| they're suddenly easy. But up until that moment, they're slippery
| eels.
|
| I'm sort of a C beginner myself. I understand pointers, and I do
| remember they clicked in my mind suddenly. The moment before, I
| didn't understand at all. I also love the quirkiness of this
| guide. Definitely going to give this a read.
| andi999 wrote:
| Do you mean the general concept or like: a is a pointer to an
| array of functions which return pointers to functions which
| return ints and take double arrays as parameters.
|
| This somehow never really clicked (or actually it clicked and
| declicked somehow)
| caseyavila wrote:
| For me it was the practical understanding. I understood the
| concept of a pointer, but I wasn't confident in writing code
| that used that used them or (more importantly) reading code.
| I would see an asterisk, multiple asterisks, or ampersands,
| and would get confused with the code. I do think some of the
| issues I encountered had to do with the notation of pointers.
| The asterisk serving as a symbol to both declare a pointer
| variable and dereference one.
| jmiskovic wrote:
| If you always read from right to left (and put occasional
| braces for readability) you can get through anything. Most
| tricky ones are in job interviews, while ones found in the
| wild will often make use of typedefs to break down the
| complexity.
| quyleanh wrote:
| Nice. But is there any like-this guide in Rust?
| RJIb8RBYxzAMX9u wrote:
| The Rust Programming Language[0] is the officially endorsed
| guide. I thought it was a good starting point.
|
| [0] https://doc.rust-lang.org/book/
| dcchambers wrote:
| Beej's Guide to Network Programming helped me survive a grad-
| level computer networking class as a naive undergrad in college.
|
| If his guide to C is anywhere near as good it should be an
| awesome resource.
| beej71 wrote:
| The C Guide is still rough around the edges (and even some in
| the center). But I'm working on it! :-)
| tumblewit wrote:
| From the creator of the famous Network programming in C guide.
| Flex247A wrote:
| Thank you for posting!
| 3rly wrote:
| I see a lot of people making opinions that clearly shows that
| they have not audited the entire guide. For the intended audience
| that the author wanted to reach. I will say that he accomplished
| it.
|
| For anything that one finds as mistakes, the author went out of
| his way (via references) for the reader to dig further.
___________________________________________________________________
(page generated 2021-04-23 23:02 UTC)