Advice forgotten:
- you should always avoid library whose API documentation are unaccessible or poorly written;
- unix man page is a great format but windows has good help format too (synopsis, signature, use case, error handling, meaning of constants, caveats),
- always check every function you are using from time to time ... human memory is not perfect, even open/calloc ....;
- don't copy paste example code blindly from man or stackoverflow ... (I remember windows C++ doc having horrible example with bugs);

Have a reference to the norm easily accessible and don't use options of the compiler which impact you don't fully know.

Most developer are poorly understanding multithreading and it can be tricky to make a portable library that has this property. Don't hesitate to stipulate in your documentation that you did not cared about it, people can then use languages with GIL (ruby, python ...) to safely overcome this issue.

Modern language are social, take advantage of sociability (nanomsg, swift, extension, #include "whatever_interpreter.h" ....).

Programming in C with dynamic structures is guaranteed to be like a blind man walking in a mine field: you totally have the right either to make C extension to modern language OR include stuff like python.h and use python data structure managed by the garbage collector from C.

Old style pre allocated arrays may not be elegant, but that's how critical system avoid a lot of problems.

DO NOT USE MAGIC NUMBERS...

USE GOTO for resource cleaning on error and make the label of the goto indentend at EXACTLY the same level the goto was written, especially when you have a resources that are coupled (ex: a file and a socket). Coupling should be avoid, but sometimes it cannot. Remember Djikstra is not that smart, he was unable to be a fully pledged physicist that can deal with the real world.

Avoiding the use of global variable is nice, but some are required, don't fall for the academic bias of hiding them to make your code look like it has none.

Copy pasting function is not always stupid (especially if you use only 1 clearly understandable function out of a huge library).

Be critical: some POSIX abstraction like threads seems to be broken by complexity: KISS.

Modern C compiler are less and less deterministic, learn about C undefined behaviour and avoid clang or GNU specific optimisations and CHECK your code gives the same results with at least 2 compilers.

Don't follow advices blindly: there are some C capos out there that dream an ideal world. Code with your past errors in mind and rely on your nightmarish past experiences to guide you to avoid traps. Feeling miserable and incompetent is some time good.

Resources are limited : ALWAYS check the results of resource exhaustion in C instead of relying on systems and always have error messages preallocated and preferably don't i18n them. Don't trust the OS to do stuff for you (closing files, SIGSEV/SEGFAULT ...).

KISS KISS KISS complexity is your enemy in C much more than in other languages. Modern C/C++ want you to build complex architecture on libraries that are often bloated (glibc).

Egyptians are nice looking.

Once you finished coding you have done only the easy part in C:
- dependency management is hard in C;
- have a simple deterministic build chain;
- you should write your man pages too;
- you should aim at writing portable code;
- static code analysis, maybe fuzzing, getting rid of all warnings is the last important part.

Coding in C is just about 15% of the time required to make great software. You will probably end up debugging it much more than you write it: write code for maintainability as your first priority and do not under any circumstances think that you can handle multiple priorities (memory use, speed, ...).

Above all : just write maintainable code, please. This rule is the golden rule of C and it has not changed.