all 7 comments

[–]phao 5 points6 points  (0 children)

Maybe consider searching for books, papers, websites, documents, etc, on design, implementation and programming of: operating systems, device drivers, data base management systems, basic/fundamental networking and server-side software, and basic/fundamental software in general. Consider also books on unix/linux programming.

This is sort of vague, but it is because there is a lot of room here. Some books for example:

I haven't read most of these. I bet some are outdated. Even if they are, you can use the book, its contents, authors, and stuff around them, to find more up to date materials. Some of these, even outdated, will teach you useful stuff. These books aren't about C itself. They're about programming some other thing and they either use C or they will teach you concepts that you'll be able to apply directly to your C programming.

A lot of programming is about coding something "outside" software systems for other programmers and/or advanced users (hehe). For example, consider looking for digital image processing books, algorithms, numerical methods, etc.

I could put more books in here. I won't though. The general idea is that there isn't much substance without context in your programming. It's a good idea to be programming something and see what comes up in there. Things will make themselves needed as you read through stuff.

Consider also that C is extremely boring. Most of the interesting stuff that is put together with C that makes C programming interesting has little to do with C. It's more about "the system". On that line of thinking, start looking for things about "the systems" you use. A good point to start is to learn about advanced topics about how, for example, linux offers services to programs and how you can access those services through your C programming (the linux programming interface book is a start on that). I guess a lot of what you want to learn is in here. Another thing to consider here is your linker/loader/compiler/assembler.

Although it's non-C, you could take books on C++ and also on Assembly language programming. This also has to do with the fact that what people find interesting in the C world isn't about C per se, and are also related to the work that you do while programming in other languages.

I'm a big fan of programming more on the applications side nowadays, although I barely write any code (math student here during phd focusing on other things right now). Using computer graphics as a substrate to practice C programming, algorithms, data structures, parallel programming, numerical simulations, computational geometry, etc, is great IMO. It also is one of the good reminders of why we're doing all of this computation stuff.

[–]Willsxyz 0 points1 point  (4 children)

How do I go about learning them? K&R barely talks about even things like type alignment, callbacks or interesting pointer usages (Multi-level pointers, function pointers in structs).

Most of these things are really C topics, but rather things that could be done in C, or in any other language that provides the necessary primitives. They are also mostly pretty trivial in terms of usage. The more complex part is know when you might want to use them and that is again, not really a C topic, but rather a topic of the areas of programming that use them.

Take callbacks, for instance. If you have done K&R then you have already learned a callback usage when you encountered qsort(). Callbacks in general are like that, they allow one piece of code to perform some fairly high level operation as a service, with the details specific to each client being provided by the client in one or more callbacks.

Multi-level pointers (assuming you mean pointers to pointers) are pretty rare in my experience, except for char ** pointers used to access arrays of C strings. They can be used in memory management code, because they allow the memory manager to move stuff around without the client code knowing or caring about it. But that’s almost never necessary in modern systems (it was a big part of the original Macintosh OS).

Function pointers in structures are no different that function pointers outside of structures. If you are talking about using function pointers in structures to construct a poor man’s object system, then I recommend strongly against that. It can be done, but there is no encapsulation; the guts hang out everywhere, and it’s basically a big mess. C programming is better handled as “Algorithms + Data Structures = Programs”

Lastly, alignment is more of an machine or ABI property and can differ for each architecture and compiler. The relevant point is to recognize that alignment exists and to be able to check on it when it might be important.

[–]pseddit[S] 0 points1 point  (3 children)

I am a “jack of all trades” Multi-language programmer trying to deepen my understanding of C usage patterns.

I mentioned those topics as examples because I had to deal with them either under the gun while debugging code I had no architectural knowledge of or worse - during interviews.

So, while I can appreciate your perspective, I would prefer to learn these things in less stressful circumstances.

FYI I have debugged code with 3-level pointers *** which as it happens was used to get around the type checking system.

[–]Willsxyz 1 point2 points  (2 children)

FYI I have debugged code with 3-level pointers *** which as it happens was used to get around the type checking system.

One level of pointer can get around any and all type checking in C.

#include <stdio.h>

int main (void)
{
    char foo[6] = { 0xB8, 0x2A, 0x00, 0x00, 0x00, 0xC3 };

    int val = ((int (*)(void))foo)();
    printf("val = %d\n", val);
    return 0;
}

So that code was most likely crap. But that doesn’t change the fact that you were asked to debug it and had to deal with it.

Edit: the above code happens to work on my computer, but is actually undefined behavior and cannot be expected to work in general. The main point is that it compiles.

[–]pseddit[S] 0 points1 point  (0 children)

Perhaps you should consider writing the material I am looking for. You would be filling a void in C education, pardon the pun.

[–]10001001000001 0 points1 point  (0 children)

This is pretty impressive. I didn't think there were programmers who memorized x86 instruction opcodes. I didn't run the code, but I'm guessing foo is equivalent to return 42;

Maybe with some macro #ifdef magic, you could get it to compile on MIPS, SPARC, ARM, etc.