hello friends! new(ish)!

C Help and Discussion: Difference between revisions

From InstallGentoo Wiki v2
Jump to navigation Jump to search
>Emil
m (added direct downloads.)
No edit summary
 
(86 intermediate revisions by 7 users not shown)
Line 1: Line 1:
[[File:Clogotrans.png|200px|thumb|right|The C Programming Logo]]
[[File:Clogotrans.png|400px|thumb|right|The C Programming Language Logo]]
[[File:C.png|250px|thumb|The Real Logo]]
[[File:Gigachad.jpg|200|thumb|This may be you after using C]]
[[File:G_programming_challenges.png|thumb|320px|/g/ Programming Challenges]]
[[File:G_programming_challenges.png|thumb|320px|/g/ Programming Challenges]]
[[File:Ken Thompson and Dennis Ritchie--1973.jpg|thumb|The Boys]]
[[File:Ken Thompson and Dennis Ritchie--1973.jpg|thumb|The Boys]]
[[File:The C Programming Language, First Edition Cover.png|thumb|260px|The Bible]]
[[File:The C Programming Language, First Edition Cover.png|thumb|260px|The Bible]]
 
[[File:You.And.Your.Bible.jpg|thumb|260px|You And Your Bible]]


C Help and Discussion - or /chad/, is a ongoing general where people discuss all things C.
C Help and Discussion - or /chad/, is a ongoing general where people discuss all things C.
Line 15: Line 17:
== Template ==
== Template ==


  Lets have a C thread. Post what your working on! Show what your interested in now.
  /chad/ - C Help And Discussion #...
 
Let's have a C thread. Post what you're working on! Show what you're interested in!
Last thread: >>...
   
   
  Last thread(s) : >>OLD...
  WIKI: https://wiki.installgentoo.com/wiki//chad/
   
   
  WIKI : https://wiki.installgentoo.com/wiki/C_Help_and_Discussion
  IRC: #/g/chad at irc.rizon.net
  IRC  : irc.rizon.net channel #/g/chad
  TG: https://t.me/+itOpQDA2Nbk3ZDZh
   
   
  Don't know how to write C? Start here:
  Don't know how to write C? Start here:
  K&R PDF: https://files.catbox.moe/80f07b.pdf
  K&R: https://files.catbox.moe/rfhegv.pdf<!-- updated pdf from thread #25 OP -->
King PDF: https://files.catbox.moe/7zgskj.pdf
KING: https://files.catbox.moe/a875c2.pdf
Modern C: https://files.catbox.moe/xeb93p.pdf
 
If you want to be a daredevil and let the C++oids in, use this header instead:
Let's have a C/C++ thread. Post what you're working on! Show what you're interested in!
 
Note that if this becomes a consistent trend in threads this page would probably need to add some filthly C++ resources, what a sad thing to say.
<!-- Matrix, both very under used and not recommend to join or use currently.
[https://element.scyldings.com/#/room/#gigachad:scyldings.com The old unmoderated Matrix].
[https://matrix.to/#/#chad:data.haus The other Matrix, Noone I know uses this.] -->
 
== Useful Links ==
=== Getting started ===
 
* [https://www.learn-c.org/en/Hello%2C_World%21 Hello World!]
* [https://en.cppreference.com/w/c Online Reference for C]
* [https://c-faq.com/ C Programming FAQs: Frequently Asked Questions]
 
=== Challenge ===
 
* [https://better-dpt-roll.github.io/ DPT Roll]
 
=== Books ===
 
* [https://files.catbox.moe/80f07b.pdf K&R C Second Edition]
* [https://files.catbox.moe/a875c2.pdf King - C Programming - A Modern Approach]
* [https://savedparadigms.files.wordpress.com/2014/09/harbison-s-p-steele-g-l-c-a-reference-manual-5th-ed.pdf C: A Reference Manual]
* [https://files.catbox.moe/cyk0ov.pdf P.J. Plauger The Standard C Library]
* [https://theswissbay.ch/pdf/Gentoomen%20Library/Software%20Engineering/B.W.Kernighan%2C%20R.Pike%20-%20The%20Practice%20of%20Programming.pdf bwk & rob - The Practice of Programming]
* [https://files.catbox.moe/vj4jpp.pdf RMS' C tutorial]
* [https://beej.us/guide/bgc/html/ Beej's Guide to C Programming]
* [https://gcc.gnu.org/onlinedocs/gcc.pdf GCC PDF]
* /g/entoomen book collection [magnet:?xt=urn:btih:0bbfaaf5f469a2bd3d762f6942a302f7014a35e9 torrent] & [https://theswissbay.ch/pdf/Gentoomen%20Library/ direct download]
 
=== Standards ===
 
* [https://web.archive.org/web/20150604055106id_/https://www.pdf-archive.com/2014/10/02/ansi-iso-9899-1990-1/ansi-iso-9899-1990-1.pdf C89/C90] '''·''' [https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf C99] '''·''' [https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf C11] '''·''' [https://web.archive.org/web/20181230041359id_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf C17] '''·''' [https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3088.pdf C23]
 
=== Articles ===
 
* [https://skeeto.s3.amazonaws.com/share/onward17-essays2.pdf Some Were Meant For C]
* [https://www.rfleury.com/p/untangling-lifetimes-the-arena-allocator Untangling Lifetimes: The Arena Allocator]
* [https://www.gingerbill.org/series/memory-allocation-strategies/ Memory Allocation Strategies]
* [https://floooh.github.io/2019/09/27/modern-c-for-cpp-peeps.html Modern C for C++ Peeps]
* [https://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html scanf guide]
* [https://codeberg.org/1414codeforge/articles/src/branch/main/drafts/structured-resource-management-in-c/article.md Structured resource management in C]
* [https://snai.pe/posts/c-smart-pointers C smart pointers]
* [https://www.bell-labs.com/usr/dmr/www/chist.html The Development of the C Programming Language*]
* [https://cs.lmu.edu/~ray/notes/gasexamples/ GNU Assembler (GAS) Examples]
* [https://pencil.toast.cafe/bunker-labs/simply-parse-in-c Simply Parse in C]
* [https://kernelnewbies.org/FAQ/LinkedLists LinkedLists from the Kernel]
<!-- * [https://grugbrain.dev/ Grug on Complexity] Not really related to C --->
* [https://www.pcg-random.org/posts/does-it-beat-the-minimal-standard.html Fast Pseudo-RNG]
 
== Libraries ==
 
<!--<sub>(List is unsorted and not categorized)</sub>--->
 
* [https://github.com/nothings/stb stb]: Single-file public domain libraries for C/C++
* [https://github.com/zyantific/zydis zydis]: disassembler & code generation
* [https://cmocka.org/ cmocka]: for testing
* [https://fragglet.github.io/c-algorithms/ C Algorithms]: Collection released under the ISC license designed to bring data structures and algorithms common in standard libraries of more modern programming languages to C.
 
==== System Libraries ====
 
* [https://www.cs.cmu.edu/afs/cs/academic/class/15492-f07/www/pthreads.html pthreads]: multithreading on UNIX systems
* [https://www.openmp.org/ OpenMP]: Cross-platform multithreading
 
==== Cryptography & Networking ====
 
* [https://curl.se/libcurl/ LibCURL]: multi-platform file transfer library
* [https://www.openssl.org/ OpenSSL]
* [https://www.libressl.org/ LibreSSL] OpenBSD's fork of OpenSSL that was created after the infamous [https://heartbleed.com/ heartbleed] CVE. Switched away from their naming scheme of usually using open as a prefix to their since obvious it is taken.
* [https://bearssl.org/ BearSSL]: Ultra-lightweight, portable, heavily-documented, MIT-licensed cryptography library with zero dynamic memory allocation and TLS 1.0-1.2 in ~30K SLOC. Supported by cURL and suitable for embedded systems.
* [https://sr.ht/~mcf/libtls-bearssl/ libtls-bearssl]: libtls implemented on top of BearSSL. Allows for drop-in replacement wherever LibreSSL's native API is supported.
* [https://www.trustedfirmware.org/projects/mbed-tls/ mbedtls]:  C library that implements cryptographic primitives, X.509 certificate manipulation and the SSL/TLS and DTLS protocols. Its small code footprint makes it suitable for embedded systems.
* [https://monocypher.org/ monocypher]: Single header cryptography library
* [http://sauerbraten.org/enet/ enet]: Minimalistic yet robust network communication layer on top of UDP.
 
==== Data ====
 
* [https://github.com/antirez/sds sds]: Simple Dynamic Strings
* [https://gmplib.org/ LibGMP]: for arbitrary-precision arithmetic
 
==== Audio ====
 
* [https://www.openal.org/ OpenAL]
* [https://miniaud.io/ Miniaudio]
* [https://solhsa.com/soloud/ Soloud]
* [https://www.portaudio.com/ PortAudio]
 
==== Graphics ====
 
* [https://www.cairographics.org/ Cairo]: for drawing pictures
* [https://www.opengl.org/ OpenGL]: for 3D rendering
* [https://www.vulkan.org/ Vulkan]: for 3D rendering
* [https://www.glfw.org/ GLFW]: for windowing for Vulkan/OpenGL
* [https://www.libsdl.org/ SDL]: for windowing and general purpose graphics
* [https://github.com/Immediate-Mode-UI/Nuklear Nuklear]: A single-header ANSI C immediate mode cross-platform GUI library
* [https://github.com/cimgui/cimgui cimgui]: C API for imgui
* [https://www.raylib.com/ Raylib]: abstracted graphic programming for vidya
 
==== Communication ====
 
* [https://zeromq.org/ zeromq]: for communication via messages
* [https://protobuf.dev/ protobuf]: for binary communication between programs in different languages
 
==== Databasing and Files ====
 
* [https://github.com/akheron/jansson Jasson]: for JSON
* [https://www.sqlite.org/index.html SQLite]: for storing data in an atomically
* [https://github.com/libuv/libuv libuv]: for cross-platform async I/O
 
==== CLI ====
 
* [https://www.gnu.org/software/libc/manual/html_node/Argp.html argp]: for extensive option parsing
* [https://www.gnu.org/software/libc/manual/html_node/Getopt.html getopt]: for simple option parsing
* [https://github.com/skeeto/optparse optparse]: a getopt-like parser
* [https://tiswww.case.edu/php/chet/readline/rltop.html readline]: for taking user input (GPLv3)
* [http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libedit/ libedit] & ([https://man.netbsd.org/editline.3 manpage]): for taking user input (BSD)
* [https://github.com/antirez/linenoise linenoise]:  BSD-licensed ultra-lightweight alternative to readline and libedit, weighing in at a under 900 SLOC. Note that it is not suitable for applications which require unicode.
* [https://www.gnu.org/software/ncurses/ ncurses]: Terminal rendering


== Tools ==
== Tools ==
=== Building and Build systems ===
=== Building and Build systems ===
==== [https://www.gnu.org/software/automake/manual/automake.pdf Autotools] ====
GNU Autotools is a build system that generates Makefiles which comply to [https://www.gnu.org/prep/standards/standards.html#Makefile-Conventions GNU Coding Standards], which makes it easier for users of your software to adjust the build process for their needs. The ability to do out-of-tree builds, cross-compilation and staged installs comes out of the box, so you don't have to implement it yourself.


[https://web.archive.org/web/20160315221623id_/http://www.dwheeler.com/autotools/autotools-introduction.webm Video guide by David A. Wheeler] '''·''' Basic Template: {{garchive|92422644|92441749}}
==== Small Scale ====
 
* [https://www.gnu.org/software/make/manual/make.pdf Makefile]: It is best to use only for small and simple projects.
 
* [https://ninja-build.org/ Ninja]: Not designed for human generation. <i>Much</i> faster make-like tool.
 
* [https://git.sr.ht/~mcf/samurai samurai]:  Significantly smaller drop-in re-implementation of ninja written in C; no C++ or Python dependencies. Used by Alpine among others as the default 'ninja'.
 
* [https://redo.readthedocs.io/en/latest/ redo]: a better, recursive, general-purpose build system.
 
==== Scalable ====
 
* [https://cmake.org/cmake-tutorial/ CMake]: CMake is a multi-platform build system that is a modern alternative to Autotools. See this [https://rentry.org/gedg-cbuild#cmake_1 /gedg/ CMake Guide.]
 
* [https://mesonbuild.com/Quick-guide.html Meson]: <sub>CMake with better syntax.</sub>


==== [https://www.gnu.org/software/make/manual/make.pdf Makefile] ====
* [https://xmake.io/#/ xmake]: Cross-platform build system written in C and Lua for rules. Suitable for projects that may typically opt for CMake or Meson. Capable of building projects directly, or generating Ninja/Makefiles like CMake/Meson. Includes an optional dependency management.  
<sub>"A Makefile a day keeps the doctor away." - me</sub>


Makefiles provide a very useful basis and if you fully grasp them, you can do most anything with enough investment. Though in most cases it's better to use Makefiles for small and simple projects.
* [https://git.sr.ht/~iemaghni/muon Muon]: Almost fully-compatible C99 reimplementation of Meson. Solid alternative for bootstrapping and the Python-averse.  


Here is a prototypical example Makefile that will cover most small-scale use cases: {{garchive|92713937|92724504}}, use <code>-s</code> in the release options instead of invoking strip directly.
* [https://www.gnu.org/software/automake/manual/automake.pdf Autotools]: GNU Autotools is a build system that generates Makefiles which comply to [https://www.gnu.org/prep/standards/standards.html#Makefile-Conventions GNU Coding Standards], which makes it easier for users of your software to adjust the build process for their needs. The ability to do out-of-tree builds, cross-compilation and staged installs comes out of the box, so you don't have to implement it yourself.
**[https://web.archive.org/web/20160315221623id_/http://www.dwheeler.com/autotools/autotools-introduction.webm Video guide by David A. Wheeler] '''·''' Basic Template: {{garchive|92422644|92441749}}


==== [https://cmake.org/cmake-tutorial/ CMake] ====
* [https://bazel.build/ Bazel] - Google's automated build and test tool designed for massive projects. Overkill and way too complicated for medium to small scale projects.  
CMake is a multi-platform build system that is a modern alternative to Autotools. <sub>It's generally considered to have bad syntax.</sub>


==== [https://mesonbuild.com/Quick-guide.html Meson] ====
=== Debugging ===
<sub>CMake with better syntax.</sub>


=== Debugging tools ===
* [https://valgrind.org/ Valgrind]: Memory leak detector, cache checker, and some other tools. (<code>-fsanitize=address</code> may be faster on average, use that instead for leaks)
* [https://splint.org/ Splint]: A C89 strict Linter
* [https://lldb.llvm.org/use/tutorial.html lldb]: LLVM project's debugger.


==== [https://valgrind.org/ Valgrind] ====
==== [https://sourceware.org/gdb/current/onlinedocs/gdb.html/ The GNU Debugger] ====


Memory leak detector, cache checker, and some other tools.
The GNU Debugger is a powerful tool allowing you to set break-points, monitor and alter code. Code should be compiled with <code>-g3</code> or <code>-ggdb</code>. It also comes with a fairly nice TUI that can be enabled by adding <code>--tui</code>. <code>~/.config/gdb/gdbinit</code>, <code>~/.gdbinit</code>, <code>~/.config/gdb/gdbearlyinit</code>, or <code>~/.gdbearlyinit</code> are respected initialization files, thus setting <code>tui enable</code> in <code>~/gdbinit</code> will have this effect by default, you may run gdb with <code>--nh</code> to disable loading from initialization files.


==== [https://splint.org/ Splint] ====
* [https://gabriellesc.github.io/teaching/resources/GDB-cheat-sheet.pdf GNU Cheat sheet]


Linter for your leg.
=== Package manager ===


==== [https://sourceware.org/gdb/current/onlinedocs/gdb.html/ gdb] ====
Optional standalone and dedicated package managers for C (or C++) that you can use as opposed to your system's general purpose package manager.


> Take your anger out on the debugger on basket weaving internet forums because you can't debug your vaporware
* [https://conan.io/ Conan]: A decentralized, open source package manager for C and C++.
* [https://github.com/cpm-cmake/CPM.cmake cpm]: CMake Package Manager. Despite its name, its not affiliated with the CMake Project.
* [https://vcpkg.io/en/ vcpkg]: Microsoft's cross-platform, free and open source C/C++ package manager for acquiring and managing libraries.
* [https://xrepo.xmake.io/#/ xrepo]: xmake's complementary package manager that uses conan's and vcpkg's repository.
* [https://hunter.readthedocs.io/en/latest/index.html Hunter]: CMake driven cross-platform package manager for C/C++.


==== [https://lldb.llvm.org/use/tutorial.html lldb] ====


Stub.
=== Compilers ===


== Recommended Build Options ==
==== Established ====
=== Warnings ===
Well established compilers used in production by overwhelming majority of C programmers.
GCC Warnings are [https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Warning-Options.html#Warning-Options listed here]. For both GCC and Clang, it is generally recommended to use <code>-Werror -Wall -Wextra -Wpedantic</code>.
* [https://gcc.gnu.org/ GCC]: The GNU Compiler Collection (Originally known as the GNU C Compiler...)
** On Windows, use [https://github.com/skeeto/w64devkit w64devkit].
* [https://clang.llvm.org/ Clang/LLVM]: An "LLVM native" C/C++/Objective-C compiler.  
** On Windows, use [https://github.com/mstorsjo/llvm-mingw llvm-mingw].
* [https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170 MSVC]: Microsoft's Proprietary C/C++ Compiler. Only available within Visual Studio which is only on Windows.
* [https://www.intel.com/content/www/us/en/developer/articles/tool/intel-system-studio-download-and-install-intel-c-compiler.html ICC]: The Intel C Compiler. Proprietary compiler that uses LLVM as its backend. Caution should be taken if used due to previous behavior by Intel (Maliciously generating slower code for non-Intel processors).
* [https://www.amd.com/en/developer/aocc.html AOCC]: AMD Optimizing C, C++, and Fortran Compiler. Proprietary fork of LLVM + Clang that adds numerous patches designed to improve performance for AMD's Zen microarchitecture that is within Epyc (server oriented) and Ryzen (desktop oriented) chips.
* [https://developer.arm.com/documentation/dui0472/latest/ armcc]: ARM's C Compiler. Has variants for server and embedded.


<code>-Werror</code>
==== Enthusiast ====
Compilers that are either developed by and for hobbyists or are still being developed.
* [https://git.sr.ht/~mcf/cproc cproc][https://github.com/michaelforney/cproc (github mirror)]: Small, optimizing C compiler using [https://c9x.me/compile/ QBE] for its backend. Supports C11 as well as portions of C23 and some GNU extensions. Unlike TCC, cproc does not include its own pre-processor or linker. However, it produces significantly more performant executables, reaching roughly ~75-80% the speed of GCC -O2 at only ~80K SLOC (counting QBE). Takes inspiration from several smaller and obscure c compilers like [https://github.com/rui314/8cc 8cc], [https://github.com/andrewchambers/c c], [https://github.com/larmel/lacc lacc], and [https://www.simple-cc.org/ scc].
* [https://github.com/RealNeGate/Cuik Cuik] - A modern C11 compiler intended to be quick hence the name. Complete toolchain built to replace GCC, MSVC, and LLVM. It's built in a modular design, the C11 frontend is one library (libCuik) along with the backend (tb / TildeBackend) which can both be compiled separately. Still being developed under the [https://github.com/RealNeGate/Cuik/tree/new-cg new-cg branch].
* [https://www.bellard.org/tcc/ TCC]: The Tiny C Compiler is notable for its extremely fast compilation speeds. Originated as a relatively small program made by Fabrice Bellard during a code competition. Bellard continued to develop it for a while after the contest but has left the project for other things. It is [https://savannah.nongnu.org/projects/tinycc still being developed by many enthusiasts including some who work on GCC].
* [https://github.com/vnmakarov/mir MIR]: Red Hat's upcoming ultra-lightweight MIT-licensed JIT compiler-backend written in C and clocking in at under 15K SLOC. Includes a usable reference C compiler (c2mir) capable of cproc-like performance. Suitable alternative to LLVM, libgccjit, and QBE for building new compilers. Targets Linux AMD64, ARM64, PPC64LE, PPC64BE, RISC-V 64, and s390x as well as macOS AMD64 and ARM64. Unlike QBE, MIR has initial support for 32-bit platforms in addition to 64-bit.
* [https://www.simple-cc.org/ scc]: The Simple C Compiler.


Make all warnings into errors.
==== Obscure ====


<code>-Wall</code>
* [https://archive.is/wyr1i pcc] - Portable C Compiler. An early C compiler made by a BELL Labs software engineer in 1973.
* [https://github.com/tyfkda/xcc XCC] - Standalone C compiler/assembler/linker/libc for x86-64/aarch64/riscv64/wasm
* [https://vaibhavweb.tripod.com/ Turbo C]: A free C++ compiler from Borland. It comes with an IDE and debugger.
* [https://compcert.org/index.html CompCert]: A C99 compiler intended for the compilation of life-critical and mission-critical software and meeting high levels of assurance. Non-free.
* [https://github.com/xoreaxeaxeax/movfuscator Movfuscator]: A single instruction (MOV) C89 compiler created for lulz by the reverse-engineering god Christopher Domas.


Enables a large set of warnings, some of which may be undesirable. Very recommended to use.
=== Linkers ===


<code>-Wextra</code>
* [https://www.gnu.org/software/binutils/ ld]: GNU's implementation of the original ld linker.
* [https://www.gnu.org/software/binutils/ gold]: A faster alternative to ld originally created by Google before being abandoned. Now also developed and distributed by GNU binutils team. ELF files only.
* [https://lld.llvm.org/ lld]: LLVM's linker.
* [https://github.com/rui314/mold mold]: An upcoming linker to serves as a drop-in replacement to existing Unix linkers.


This enables some extra warning flags that are not enabled by -Wall. Recommended to use.
=== Miscellaneous ===
* [https://github.com/friendlyanon/cmake-init cmake-init]: A random /g/entooman's Cmake project initializer.


<code>-Wpedantic</code>
== Recommended Build Options ==


Issue all the warnings demanded by strict ISO C and ISO C++; reject all programs that use forbidden extensions, and some other programs that do not follow ISO C and ISO C++. For ISO C, follows the version of the ISO C standard specified by any -std option used (Example: -std=c99).
=== Standards ===


<code>-std=</code>
<code>-std=</code> (valid: c89, c99 c11 c17, c2x) (additional: c90=c89, c18=c17). Any 'c' can be replaced with 'gnu' for GNU extensions, but you can use them anyway and the compiler won't even warn you unless you specify <code>-pedantic</code> or <code>-Wpedantic</code> so don't worry about it too much unless you're looking to maximize compiler portability.


Determine the language standard. See [https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Standards.html#Standards Language Standards Supported by GCC], for details of these standard versions. This option is currently only supported when compiling C or C++. <code>-std=c99</code> is usually a good choice.
Determine the language standard. See [https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Standards.html#Standards Language Standards Supported by GCC], for details of these standard versions. This option is currently only supported when compiling C or C++. <code>-std=c99</code> is usually a good choice.
Line 90: Line 253:
On MSVC use <code>/D_CRT_SECURE_NO_WARNINGS</code> to disable warnings regarding the so-called "secure" functions. These aren't widely supported outside of MSVC, and their benefits are questionable. See [https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1967.htm N1967] for more information.
On MSVC use <code>/D_CRT_SECURE_NO_WARNINGS</code> to disable warnings regarding the so-called "secure" functions. These aren't widely supported outside of MSVC, and their benefits are questionable. See [https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1967.htm N1967] for more information.


<code>-Wstrict-aliasing=3</code>
<code>-ansi</code>: Common alias for <code>-std=c89</code>.
 
=== Warnings ===
GCC Warnings are [https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Warning-Options.html#Warning-Options listed here]. For both GCC and Clang, it is generally recommended to use <code>-Werror -Wall -Wextra -Wpedantic</code>.
 
<code>-Werror</code>: Make all warnings into errors.
 
 
<code>-Wall</code>: Enables a large set of warnings, some of which may be undesirable. Very recommended to use.
 
 
<code>-Wextra</code>: This enables some extra warning flags that are not enabled by -Wall. Recommended to use.
 
 
<code>-Wpedantic</code>: Issue all the warnings demanded by strict ISO C and ISO C++; reject all programs that use forbidden extensions, and some other programs that do not follow ISO C and ISO C++. For ISO C, follows the version of the ISO C standard specified by any -std option used (Example: -std=c99).
 


Pointer aliasing is when two different pointers can point to the same memory location.
<code>-Wstrict-aliasing=3</code>: Pointer aliasing is when two different pointers can point to the same memory location.
Strict aliasing is a set of rules C compilers use to determine when this can happen and when it can't.
Strict aliasing is a set of rules C compilers use to determine when this can happen and when it can't.
3 may be too high for beginners and can spit out some false-positives, 2 is typically a better choice.  
3 may be too high for beginners and can spit out some false-positives, 2 is typically a better choice.  


<code>-Wwrite-strings</code>


Warns on write to string literals, which have the type of `char []` however, writing to a string literal is Undefined Behavior (UB), so it makes more sense to treat them as `const char []` (even DMR wanted to make string literals const: https://www.lysator.liu.se/c/dmr-on-noalias.html).
<code>-Wwrite-strings</code>: Warns on write to string literals, which have the type of `char []` however, writing to a string literal is Undefined Behavior (UB), so it makes more sense to treat them as `const char []` (even DMR wanted to make string literals const: https://www.lysator.liu.se/c/dmr-on-noalias.html).
 
 
 
<code>-Wvla</code>: Warns if there is a variable length array used in the code.
VLAs are either unnecessary because you know the upper bound and are able to do <code>buf[UPPER_BOUND]</code> or are a stack overflow waiting to happen. Some smaller compilers like [https://sr.ht/~mcf/cproc cproc] do not implement VLAs, possibly avoiding use of this option may aid portability.
 
 
<code>-Wcast-align=strict</code>: can warn on some newb casting.
 


<code>-Wvla</code>
<code>-Wstrict-prototypes</code>: Warns on function declarations that lack an explicit set of parameters like <code>f()</code>, which have a specialized purpose in C and only C, where the set arguments are set at the implementation site.


Warns if there is a variable length array used in the code.
VLAs are either unnecessary because you know the upper bound and can do <code>buf[UPPER_BOUND]</code> or are a stack overflow waiting to happen.


Some smaller compilers like [https://sr.ht/~mcf/cproc cproc] do not implement VLAs, possibly avoiding use of this option may aid portability.
<code>-Wstringop-overflow=4</code>: Warns for calls to string manipulation functions such as memcpy or strcpy that are determined to overflow the destination buffer. At <code>=4</code> it additionally warns about overflowing any data members, and when the destination is one of several objects it uses the size of the largest of them to decide whether to issue a warning.


<code>-Wcast-align=strict</code>


can warn on some newb casting.
<code>-Wno-logical-op-parentheses</code>: C has an order precedence of first <code>&&</code> then <code>||</code>. This is however warned against, and at a glance with this knowledge it is much easier to tell the difference between <code>(a && b || c)</code> and <code>(a && (b || c))</code> than enforcing that warning like <code>((a && b) || c)</code> and <code>(a && (b || c))</code>.


<code>-Wstrict-prototypes</code>


Warns on function declarations that lack an explicit set of parameters like <code>f()</code>, which have a specialized purpose in C and only C, where the set arguments are set at the implementation site.
<code>-Wshadow</code>: Warns when a block re-declares a variable already declared in a higher block. This is often done intentionally but beginners may wish to be warned on it because the bugs it can cause are particularly subtle and difficult to debug, since the debugger will not tell you what the actual problem is.


<code>-Wstringop-overflow=4</code>


Warns for calls to string manipulation functions such as memcpy or strcpy that are determined to overflow the destination buffer.
<code>-Weverything</code>: Exclusive to clang and only intended for developing clang itself. May require many <code>-Wno-...</code> options to not emit too many false positives, but the perfectionist or anon who simply can't be bothered to run a linter may find it useful.
At <code>=4</code> it additionally warns about overflowing any data members, and when the destination is one of several objects it uses the size of the largest of them to decide whether to issue a warning.


<code>-Wno-logical-op-parentheses</code>


C has an order precedence of first <code>&&</code> then <code>||</code>. This is however warned against, and at a glance with this knowledge it is much easier to tell the difference between <code>(a && b || c)</code> and <code>(a && (b || c))</code> than enforcing that warning like <code>((a && b) || c)</code> and <code>(a && (b || c))</code>.
<code>-fanalyzer</code>: Perform advanced static analysis. Massively increases compile times but can catch nontrivial memory errors and does not impart a runtime performance penalty unlike <code>-fsanitize=</code> (see below).


=== Optimizing & Release options ===
=== Optimizing & Release options ===
GCC optimization options can be [https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Optimize-Options.html#Optimize-Options seen here].
GCC optimization options can be [https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Optimize-Options.html#Optimize-Options seen here].


<code>-O2 -DNDEBUG</code>
<code>-O0</code>: Reduce compilation time and make debugging produce the expected results. This is the default.


Provides good optimizations for most use-cases.


<code>-O0</code>
<code>-O1</code>: Optimize. Optimizing compilation takes somewhat more time, and a lot more memory for a large function. With <code>-O</code>, the compiler tries to reduce code size and execution time, without performing any optimizations that take a great deal of compilation time.


Reduce compilation time and make debugging produce the expected results. This is the default.


<code>-O</code> or <code>-O1</code>
<code>-O2</code>: Optimize even more. GCC performs nearly all supported optimizations that do not involve a space-speed tradeoff. As compared to <code>-O</code>, this option increases both compilation time and the performance of the generated code.


Optimize. Optimizing compilation takes somewhat more time, and a lot more memory for a large function.
With <code>-O</code>, the compiler tries to reduce code size and execution time, without performing any optimizations that take a great deal of compilation time.


<code>-O2</code>
<code>-O3</code>: Enables all optimizations specified by <code>-O2</code> and some additional flags. Can drastically increase binary size due to loop unrolling, particularly with clang. It is somewhat overfitted to x86-64 processors, and other architectures may actually see worse performance with this option even with an appropriate <code>-march</code>.


Optimize even more. GCC performs nearly all supported optimizations that do not involve a space-speed tradeoff. As compared to <code>-O</code>, this option increases both compilation time and the performance of the generated code.


<code>-O3</code>
<code>-Ofast</code>: Disregard strict standards compliance. Enables all <code>-O3</code> optimizations. It also enables optimizations that are not valid for all standard-compliant programs. It turns on <code>-ffast-math</code>, <code>-fallow-store-data-races</code> and the Fortran-specific <code>-fstack-arrays</code>, unless <code>-fmax-stack-var-size</code> is specified, and <code>-fno-protect-parens</code>. It turns off <code>-fsemantic-interposition</code>. Do not use this if your code relies on specified IEEE float behavior or if you have multiple threads accessing the same data, even with locks. Even if your code doesn't, extensive testing is required to guarantee you can get away with this flag, and the benefit is small even when you can. Avoid if you are a beginner.


Optimize yet more. <code>-O3</code> turns on all optimizations specified by <code>-O2</code> and some additional flags.


<code>-Ofast</code>
<code>-Os</code>: Optimize for size. Enables all <code>-O2</code> optimizations except those that often increase code size. It also enables <code>-finline-functions</code>, causes the compiler to tune for code size rather than execution speed, and performs further optimizations designed to reduce code size. Generally not recommended due to its "hyper-focus" on minimizing the size of a program, even at the expense of obvious, highly beneficial optimizations.


Disregard strict standards compliance. <code>-Ofast</code> enables all <code>-O3</code> optimizations. It also enables optimizations that are not valid for all standard-compliant programs. It turns on <code>-ffast-math</code>, <code>-fallow-store-data-races</code> and the Fortran-specific <code>-fstack-arrays</code>, unless <code>-fmax-stack-var-size</code> is specified, and <code>-fno-protect-parens</code>. It turns off <code>-fsemantic-interposition</code>.


<code>-Os</code>
<code>-Oz</code>: Optimize strongly for size. The difference is small for gcc, but clang's <code>-Os is not nearly as aggressive as gcc's, so the difference there is larger.</code>


Optimize for size. <code>-Os</code> enables all <code>-O2</code> optimizations except those that often increase code size. It also enables <code>-finline-functions</code>, causes the compiler to tune for code size rather than execution speed, and performs further optimizations designed to reduce code size.
Generally not recommended due to its "hyper-focus" on minimizing the size of a program, even at the expense of obvious, highly beneficial optimizations.


<code>-Og</code>
<code>-Og</code>: Optimize debugging experience. Should be the optimization level of choice for the standard edit-compile-debug cycle, offering a reasonable level of optimization while maintaining fast compilation and a good debugging experience. It is a better choice than <code>-O0</code> for producing debuggable code because some compiler passes that collect debug information are disabled at <code>-O0</code>. Like <code>-O0</code>, <code>-Og</code> completely disables a number of optimization passes so that individual options controlling them have no effect. Otherwise <code>-Og</code> enables all <code>-O1</code> optimization flags except for those that may interfere with debugging.


Optimize debugging experience. <code>-Og</code> should be the optimization level of choice for the standard edit-compile-debug cycle, offering a reasonable level of optimization while maintaining fast compilation and a good debugging experience. It is a better choice than <code>-O0</code> for producing debuggable code because some compiler passes that collect debug information are disabled at <code>-O0</code>. Like <code>-O0</code>, <code>-Og</code> completely disables a number of optimization passes so that individual options controlling them have no effect. Otherwise <code>-Og</code> enables all <code>-O1</code> optimization flags except for those that may interfere with debugging.


<code>-flto=N</code> LTO provides Link time optimization, try <code>-flto=auto</code> on release builds.  
<code>-flto=auto</code>: Perform link-time optimization. There is some confusion about LTO because the supported way to do it has changed a lot over the years but in 2023 with gcc 13 or clang 16 just using <code>-flto=auto</code> should make everything just work. Or, you may need <code>SET(CMAKE_AR  "gcc-ar")</code> and <code>SET(CMAKE_RANLIB "gcc-ranlib")</code> when using cmake because cmake hates using gcc correctly for some reason. And with clang you may need <code>-fuse-ld=lld</code> because Ubuntu is shit. There is quite a bit of difference between how LTO works between gcc and clang. With clang, <code>-flto=auto</code> is an alias for <code>-flto=full</code>, which treats the entire program as one codegen unit at the cost of parallelism. Clang can only parallelize LTO with <code>-flto=thin</code>, which skips many optimizations. This is distinct from the concept of thin LTO objects in gcc which are just object files with only GIMPLE bytecote and no machine code so they require LTO at link-time to be used. Note that the reverse is never true: executables compiled with LTO will happily link against objects and static libraries that lack it with no problem (except foregone performance). In gcc you do not need to worry about this full/thin tradeoff because whole-program analysis is performed unconditionally. In particular, you DO NOT need <code>-flto=1</code>, <code>-fuse-linker-plugin</code>, <code>-ffat-lto-objects</code>, <code>-fwhole-program</code>, or <code>-flto-partition=one</code> to squeeze the maximum performance out: gcc will prove its LTO partitions do not forego any optimizations. The <code>-flto=N</code> option only controls how many jobs the LTO wrapper can accept at once, it does not parallelize the jobs themselves. The jobs will be parallelized by <code>-flto-partition=balanced</code> (the default) in a way that still catches all optimizations. The LTO plugin is loaded automatically when passing <code>-flto</code> to gcc. <code>-fwhole-program</code> manually guarantees what the plugin has already either proven true or false, so it will either not help or will introduce UB. Don't use it. <code>-ffat-lto-objects</code> allows objects and static library archives to be linked against executables that do not themselves use <code>-flto</code>, and should be left off unless you want LTO to silently break and not tell you. It has nothing to do with fat LTO in Rust. Make sure you use the <code>=auto</code> part or you will bottleneck your Makefiles for no reason because you are only allowing one lto-wrapper to run at once despite that fact that the parallelism has no drawbacks. Or, in the case of clang, you are getting parallelism but with big drawbacks so <code>=auto</code> turns it off. At any rate when using a Makefile the number of threads used for LTO with <code>=auto</code> is capped at <code>-j</code> so you don't need two <code>$(nproc)</code> calls. For more information, see [https://documentation.suse.com/sbp/all/html/SBP-GCC-10/index.html#sec-gcc10-lto here]. '''TL;DR''': Just use <code>-flto=auto</code>! Reading all the wrong StackOverflow answers about this is giving me brain damage!


<code>-fwhole-program</code> provides optimization by the knowledge of 'this is the whole program' whether or not that is true, in principle it provides no advantage.
You cannot use it for compiling libraries because the symbols need to be externally visibly in those cases, but for making a binary all you should need exposed is _start and main, which this flag preserves.


<code>-s and strip</code> strip is primarily useful for release builds, it strips unneeded symbols and can be invoked at link-time with <code>-s</code> or seperately after the fact with <code>strip PROGRAM</code>
<code>-march=native</code>: Optimize the code for your processor. This is of limited usefulness with gcc since it barely auto-vectorizes compared to clang, but it will still enable any code paths conditional on architecture support and will take caching and microarchitecture behaviors into consideration. If you're using a specific microarchitecture like <code>znver2</code> or <code>native</code>, you DO NOT need to also use <code>-mtune</code>.


=== Debug options ===
Generally <code>-Og -g -fsanitize=address,undefined</code>, use <code>-ggdb</code> instead of <code>-g</code> if you intend to use GNU Debugger.
<code>-fsanitize=...</code> has many other useful features described in [https://gcc.gnu.org/onlinedocs/gcc.pdf#254 The GCC PDF]. 


Tools like [https://valgrind.org/ Valgrind], [https://splint.org/ Splint] will help you debug and improve your code.
<code>-s and strip</code>: strip is primarily useful for release builds, it strips unneeded symbols and can be invoked at compile- or link-time with <code>-s</code> or separately after the fact with <code>strip PROGRAM</code>


=== Diagnostic options ===
Consider <code>-fno-diagnostics-show-caret</code> for GCC or <code>-fno-caret-diagnostics</code> for Clang to reduce the number of lines per actual error in the compiler output.


== C Misconceptions ==
<code>-pipe</code>: Use pipes instead of temporary files when compiling. Saves your SSD for negligible (probably) compile-time memory cost.
=== C is too small of a language to be useful! ===
While C is a relatively small language, it provides enough facilities to create anything you can imagine. It's no secret that most interpreted languages like Perl, Python, Lua, and countless Lisps/Schemes/Forths are implemented in C. Anything you can implement in the aforementioned languages, can also be implemented in C. This could be said about many small languages which [http://catb.org/~esr/jargon/html/T/Turing-tar-pit.html aren't usable at all], but C provides enough tools of abstraction to be useful in projects of any scale, from <code>/usr/bin/true</code> to <code>/boot/vmlinuz</code>.


On the other hand, C's simplicity makes it much easier to learn the whole language. Anyone with previous programming experience can learn the entirety of C in just a few weeks. After learning the language itself, one spends the rest of their C programming career figuring out the best way to apply it. This is more productive, as you're gaining actual CS knowledge and not focusing on superficial things like a particular language's syntax/implementation details.
=== C has no package manager! ===
C has many, many package managers, one for every GNU/Linux Distribution.
Language-specific package managers [https://michael.orlitzky.com/articles/motherfuckers_need_package_management.xhtml tend to be a bad idea anyway]


=== C's lack of memory safety leads to buggy programs! ===
<code>-f1337-epic-option</code>: Some of these are useful if you are minifying a nolibc executable but in general if you are a beginner or are just looking for performance these will just cause you headaches. Stick to the basics: <code>-O3</code>, <code>-flto=auto</code>, <code>-march=native</code>, <code>-pipe</code>, <code>-s</code>.
Good coding habits will prevent many such bugs.
There are also tools like ASan and UBSan which help find memory bugs during testing.
== Useful Links ==
=== Getting started ===


* [https://www.learn-c.org/en/Hello%2C_World%21 Hello World!]
* [https://c-faq.com/ C Programming FAQs: Frequently Asked Questions]


=== Challenge ===
'''NOTE''': Optimizers aren't magic. Your code will still be slow if it's shit. See [https://www.youtube.com/watch?v=WDIkqP4JbkE this talk] for just the tip of the iceberg. Don't use linked lists just because they're easy!


* [https://better-dpt-roll.github.io/ DPT Roll]
=== Debug options ===
Generally <code>-Og -g</code>, use <code>-ggdb</code> instead of <code>-g</code> if you intend to use GNU Debugger.
<code>-fsanitize=...</code> has many useful features described in [https://gcc.gnu.org/onlinedocs/gcc.pdf#254 The GCC PDF], you however cannot combine some directives with any debugger. The most common ones are <code>address</code> and <code>undefined</code>.


=== Books ===
Tools like [https://valgrind.org/ Valgrind], [https://splint.org/ Splint] may also help you debug and improve your code.


* [https://files.catbox.moe/80f07b.pdf K&R]
=== Diagnostic options ===
* [https://files.catbox.moe/7zgskj.pdf King - C Programming - A Modern Approach]
Consider <code>-fno-diagnostics-show-caret</code> for GCC or <code>-fno-caret-diagnostics</code> for Clang to reduce the number of lines per actual error in the compiler output.
* [https://savedparadigms.files.wordpress.com/2014/09/harbison-s-p-steele-g-l-c-a-reference-manual-5th-ed.pdf C: A Reference Manual]
* P.J. Plauger The Standard C Library
* [https://files.catbox.moe/vj4jpp.pdf RMS Guide]
* [https://gcc.gnu.org/onlinedocs/gcc.pdf GCC PDF]
* [magnet:?xt=urn:btih:0bbfaaf5f469a2bd3d762f6942a302f7014a35e9 /g/entoomen book collection torrent]
* [https://theswissbay.ch/pdf/Gentoomen%20Library/ /g/entoomen book collection direct download]


=== Standards ===
== Other Recommendations ==
* [https://web.archive.org/web/20150604055106id_/https://www.pdf-archive.com/2014/10/02/ansi-iso-9899-1990-1/ansi-iso-9899-1990-1.pdf C89/C90] '''·''' [https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf C99] '''·''' [https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf C11] '''·''' [https://web.archive.org/web/20181230041359id_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf C17] '''·''' [https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3088.pdf C23]


=== Articles ===
==== <sub>Thread 23: {{garchive|94944789}}</sub> ====
* [https://skeeto.s3.amazonaws.com/share/onward17-essays2.pdf Some Were Meant For C]
* [https://www.rfleury.com/p/untangling-lifetimes-the-arena-allocator Untangling Lifetimes: The Arena Allocator]
* [https://www.gingerbill.org/series/memory-allocation-strategies/ Memory Allocation Strategies]
* [https://floooh.github.io/2019/09/27/modern-c-for-cpp-peeps.html Modern C for C++ Peeps]


=== Notable Projects Summited ===
Anonymous {{garchive|94944789|95011850}}
should i pass structs as parameters, or only a pointer to the struct.


* [https://github.com/trevarj/dotris Dotris - NCurses Tetris]
Anonymous {{garchive|94944789|95012180}}
* [https://github.com/bratpeki/teachess TeaChess - SDL2 Chess]
The usual rule of thumb is if you can fit the struct into 2 registers then pass it by value, otherwise by pointer. In reality it's more complicated. There are semantic reasons for wanting to accept by value, e.g. to make the code easier to work with. If the function is static then it's basically always fine to pass it by value because the optimizer can change it to accept a pointer (assuming you don't modify the copy of the struct), similar thing with returning structs by value, the compiler will allocate stack memory and pass in a pointer that will be filled instead of having it copied out. If you compile with LTO then this can happen across translation unit boundaries for non-static functions, but without LTO the compiler has to abide by the target ABI. In this case it's usually better to pass by pointer using the previous rule of thumb, but if you read the ABI spec for your target you will find that it's more complicated than if it can fit in 2 registers, there are a bunch of rules that determine whether a parameter is passed in a register or copied as an argument to the stack. Really the cost for non-optimized function calls is determined by the parameter passing rules defined in the target ABI, the cost memory lookup on the target, and whether the struct is in cache or not.
* [https://codeberg.org/xolatile/chad Chad - C Highlighter]
* [https://gitlab.com/Meithal/cisson Cisson - JSON I/O]


== Advice ==
==== <sub>Thread 0: {{garchive|92317404}}</sub> ====
This section exists to show off some cool /advice/ from the thread, it not really about anything precise.
If you see a really well written post, that gives a good breadth of advice, add it below.


=== How to be an Above-Average Programmer starting from University ===
Anonymous {{garchive|92317404|92317996}}
<sub>From {{garchive|92422644|92426366}}, slightly edited:</sub>
>>92317404 (OP)
How do I into C? I know a few other programming languages, so I'm less interested in syntax and such. But more best practices.


If you are in University, I think it's a good idea to supplement the classes with your own extra learning in the niches you see yourself in in the future. There's also no harm in learning things earlier than planned in your syllabus (see also: https://sive.rs/kimo). If anything, it will make it easier to get good grades and also solidify the material in your mind by going over it twice. However, it shouldn't be taken to an extreme where you're spending every waking hour in front of the computer and neglect your health or social life. Balance is important too.
Anonymous {{garchive|92317404|92340750}} (pruned)
>>92317996
My tips:
>Compile with -Wall -Wextra. In debug builds, use sanitizers too.
>For complex cross-platform programs CMake or meson can be helpful, but for simple programs make is often sufficient.
>Don't overuse the preprocessor. Use something else if possible without too much hackery. For example, sometimes you can use an inline function. For int constants, you can use enum instead of #define.
>You can organize a larger program by using prefixes. E.g. all color functions start with color_ and are in color.c/color.h, random generators start with rnd_ and are in rnd.c/rnd.h.
>Prefer reentrant to non-reentrant functions, e.g. strtok_r instead of strtok. Also avoid any string functions which can cause buffer overflow because they don't take a length, e.g. strcat or gets.


University teaches you a lot of things, but there is often not enough time to cover everything in as much detail as needed to actually get good at programming. For example, I learned enough C to write a simple game but didn't know about arena allocators, struct padding, aliasing and restrict, cache locality, CMake. They taught me how to write one-file Python scripts but not how to organize larger projects with modules, virtualenv, requirements.txt, etc.
Anonymous {{garchive|92317404|92318458}}
>>92317996
Avoid malloc'ing & returning the malloc'd memory from your functions. Instead, have them accept a buffer pointer + size to write to. Keep free's as close to their malloc's as possible.
Don't use any string functions other than strnlen. Each string handling function has its own peculiar way to handle the \0 that you have to remember, and they barely save you any time compared to just doing the pointer arithmetic yourself & using memcpy. strcat is particularly notorious for tempting you into writing accidentally quadratic code.
Keep your statements short and simple. Reading & writing to a variable in the same expression is undefined behavior. The order of evaluation of the arguments to a function is also unspecified, so don't write shit like f(a++, b, a+c) expecting a particular evaluation order.
Turn on all possible compiler warnings & use -Werror.
Define as few globals as possible. If you have to, try to keep them static to their translation unit.
Macros are shit, but unavoidable. When defining them, parenthesize all your macro args and avoid repeating them, lest you'll accidentally mutate state twice when invoking them.
Macros that expand to expressions should have their whole definitions wrapped in parentheses.
Macros that expand to statements should have their whole definitions wrapped in a do{...}while(0) statement with no trailing semicolon.
C programmers love linked lists. Expect to run into lots of them while reading C code. If you wanna know why, try implementing a growable array in C.


Above all, it's worth the effort to practice "professional" development early. In a lot of universities you can get by writing many small programs (<1000 lines) so you never get practice with larger ones. Start some multi-month and multi-thousand-line-of-code projects - either personal or a university project that might use in multiple classes. Use all the standard practices: host it on GitHub/GitLab/Codeburg/etc - It can be private if you're shy. Write [https://cbea.ms/git-commit/ good commit messages]; write a nice README.md; use Make/CMake/Meson and write down build instructions; use a readable coding style and refactor from time to time; write some tests with CMocka for the tricky algorithmic parts. After you get some practice, try contributing to open source projects! They often have a bunch of bugs in their issue tracker that aren't a priority but they'll still happily take fixes for.
Xolatile {{garchive|92317404|92335411}}
> Avoid malloc'ing & returning the malloc'd memory...
Actually, using 'calloc' is safer referring to Splint (very strict C99 linter) because it defines allocated memory segment, fills it with 0s, and validates a type if used correctly...
> Turn on all possible compiler warnings...
I completely agree, and I use different compilers with maximum warnings enabled with -Werror only in "finishing stage", along with Valgrind (always) and Splint (sometimes).
> Define as few globals as possible.
It's best to have no global variables, pass variables to functions like a proper programmer, state is the root of a lot of hard to track bugs. (:
> Macros are shit, but unavoidable.
I usually have 0 macros in my programs, I define constants inside enumerations. I don't use ifdef, ifndef, define, endif, etc. because I don't write cross-platform programs...
Due to autism, sometimes I don't even use #include, but instead write "extern ..." at the start of my source code files, or pass -include flag to compiler...
--
I missed this when it was posted Anon, but I agree with most of your points, except macros mostly, they should be avoided at all cost, especially function-like macros. (:
I usually implement my own "printf" without variadics, passing in a format as string, and array of union of basic types.


Here's why I advise to do larger, more "professional" projects early and contribute to open source: I've found that working on non-trivial programs is like a muscle that you can train, and largely independent of the language. When I was a teenager, I used to think that a 600 line program is large and A* is a complex algorithm to implement. These notions seem laughable to me now, and the change happened after I wrote a couple of 3-10 thousand line personal projects and implemented some 500+ line algorithms at university.
== C Misconceptions ==
=== C is too small of a language to be useful! ===
While C is a relatively small language, it provides enough facilities to create anything you can imagine. It's no secret that most interpreted languages like Perl, Python, Lua, and countless Lisps/Schemes/Forths are implemented in C. Anything you can implement in the aforementioned languages, can also be implemented in C. This could be said about many small languages which [http://catb.org/~esr/jargon/html/T/Turing-tar-pit.html aren't usable at all], but C provides enough tools of abstraction to be useful in projects of any scale, from <code>/usr/bin/true</code> to <code>/boot/vmlinuz</code>.


It is valuable to be able to come up with an idea for a program, write 5000 lines of code at a steady pace, and end up with something similar to the higher-quality projects you can find on GitHub: a nice commit history, a README.md that clearly explains how to build and use the software, an issue tracker with all the bugs that haven't been fixed yet, and code that's easy for people to find their way around. It's also valuable to be able to jump into someone else's codebase, quickly orient yourself, and add good code that matches the conventions of the project. These skills will give you a leg up but you don't always get them from attending university.
On the other hand, C's simplicity makes it much easier to learn the whole language. Anyone with previous programming experience can learn the entirety of C in just a few weeks. After learning the language itself, one spends the rest of their C programming career figuring out the best way to apply it. This is more productive, as you're gaining actual CS knowledge and not focusing on superficial things like a particular language's syntax/implementation details.
=== C has no package manager! ===
C has many, many package managers, one for every GNU/Linux Distribution.
Language-specific package managers [https://michael.orlitzky.com/articles/motherfuckers_need_package_management.xhtml tend to be a bad idea anyway]


<sub>Editor note: These ideas apply to even if you're not a University student, though you must define your own syllabus and you'll have to do the grading yourself. Start somewhere, and start writting code and try to follow anons advice.</sub>
=== C's lack of memory safety leads to buggy programs! ===
Good coding habits will prevent many such bugs.
There are also tools like ASan and UBSan which help find memory bugs during testing.
Large codebases may consider using [https://talloc.samba.org talloc], which provides safe wrappers around the system <code>malloc()</code> and will catch 97% of memory errors at compile- or run-time.


[[Category:Generals]]
[[Category:Generals]]
[[Category:Software]]
[[Category:Software]]

Latest revision as of 06:23, 5 November 2024

The C Programming Language Logo
The Real Logo
This may be you after using C
/g/ Programming Challenges
The Boys
The Bible
You And Your Bible

C Help and Discussion - or /chad/, is a ongoing general where people discuss all things C.

Show and talk about what your currently working on, or things you've worked on in the past.

Join our IRC channel: #/g/chad at irc.rizon.net

The past threads are enumerated here.

Template

/chad/ - C Help And Discussion #...
Let's have a C thread. Post what you're working on! Show what you're interested in!

Last thread: >>...

WIKI: https://wiki.installgentoo.com/wiki//chad/

IRC: #/g/chad at irc.rizon.net
TG: https://t.me/+itOpQDA2Nbk3ZDZh

Don't know how to write C? Start here:
K&R: https://files.catbox.moe/rfhegv.pdf
KING: https://files.catbox.moe/a875c2.pdf
Modern C: https://files.catbox.moe/xeb93p.pdf

If you want to be a daredevil and let the C++oids in, use this header instead:

Let's have a C/C++ thread. Post what you're working on! Show what you're interested in!

Note that if this becomes a consistent trend in threads this page would probably need to add some filthly C++ resources, what a sad thing to say.

Useful Links

Getting started

Challenge

Books

Standards

Articles

Libraries

  • stb: Single-file public domain libraries for C/C++
  • zydis: disassembler & code generation
  • cmocka: for testing
  • C Algorithms: Collection released under the ISC license designed to bring data structures and algorithms common in standard libraries of more modern programming languages to C.

System Libraries

  • pthreads: multithreading on UNIX systems
  • OpenMP: Cross-platform multithreading

Cryptography & Networking

  • LibCURL: multi-platform file transfer library
  • OpenSSL
  • LibreSSL OpenBSD's fork of OpenSSL that was created after the infamous heartbleed CVE. Switched away from their naming scheme of usually using open as a prefix to their since obvious it is taken.
  • BearSSL: Ultra-lightweight, portable, heavily-documented, MIT-licensed cryptography library with zero dynamic memory allocation and TLS 1.0-1.2 in ~30K SLOC. Supported by cURL and suitable for embedded systems.
  • libtls-bearssl: libtls implemented on top of BearSSL. Allows for drop-in replacement wherever LibreSSL's native API is supported.
  • mbedtls: C library that implements cryptographic primitives, X.509 certificate manipulation and the SSL/TLS and DTLS protocols. Its small code footprint makes it suitable for embedded systems.
  • monocypher: Single header cryptography library
  • enet: Minimalistic yet robust network communication layer on top of UDP.

Data

  • sds: Simple Dynamic Strings
  • LibGMP: for arbitrary-precision arithmetic

Audio

Graphics

  • Cairo: for drawing pictures
  • OpenGL: for 3D rendering
  • Vulkan: for 3D rendering
  • GLFW: for windowing for Vulkan/OpenGL
  • SDL: for windowing and general purpose graphics
  • Nuklear: A single-header ANSI C immediate mode cross-platform GUI library
  • cimgui: C API for imgui
  • Raylib: abstracted graphic programming for vidya

Communication

  • zeromq: for communication via messages
  • protobuf: for binary communication between programs in different languages

Databasing and Files

  • Jasson: for JSON
  • SQLite: for storing data in an atomically
  • libuv: for cross-platform async I/O

CLI

  • argp: for extensive option parsing
  • getopt: for simple option parsing
  • optparse: a getopt-like parser
  • readline: for taking user input (GPLv3)
  • libedit & (manpage): for taking user input (BSD)
  • linenoise: BSD-licensed ultra-lightweight alternative to readline and libedit, weighing in at a under 900 SLOC. Note that it is not suitable for applications which require unicode.
  • ncurses: Terminal rendering

Tools

Building and Build systems

Small Scale

  • Makefile: It is best to use only for small and simple projects.
  • Ninja: Not designed for human generation. Much faster make-like tool.
  • samurai: Significantly smaller drop-in re-implementation of ninja written in C; no C++ or Python dependencies. Used by Alpine among others as the default 'ninja'.
  • redo: a better, recursive, general-purpose build system.

Scalable

  • Meson: CMake with better syntax.
  • xmake: Cross-platform build system written in C and Lua for rules. Suitable for projects that may typically opt for CMake or Meson. Capable of building projects directly, or generating Ninja/Makefiles like CMake/Meson. Includes an optional dependency management.
  • Muon: Almost fully-compatible C99 reimplementation of Meson. Solid alternative for bootstrapping and the Python-averse.
  • Autotools: GNU Autotools is a build system that generates Makefiles which comply to GNU Coding Standards, which makes it easier for users of your software to adjust the build process for their needs. The ability to do out-of-tree builds, cross-compilation and staged installs comes out of the box, so you don't have to implement it yourself.
  • Bazel - Google's automated build and test tool designed for massive projects. Overkill and way too complicated for medium to small scale projects.

Debugging

  • Valgrind: Memory leak detector, cache checker, and some other tools. (-fsanitize=address may be faster on average, use that instead for leaks)
  • Splint: A C89 strict Linter
  • lldb: LLVM project's debugger.

The GNU Debugger

The GNU Debugger is a powerful tool allowing you to set break-points, monitor and alter code. Code should be compiled with -g3 or -ggdb. It also comes with a fairly nice TUI that can be enabled by adding --tui. ~/.config/gdb/gdbinit, ~/.gdbinit, ~/.config/gdb/gdbearlyinit, or ~/.gdbearlyinit are respected initialization files, thus setting tui enable in ~/gdbinit will have this effect by default, you may run gdb with --nh to disable loading from initialization files.

Package manager

Optional standalone and dedicated package managers for C (or C++) that you can use as opposed to your system's general purpose package manager.

  • Conan: A decentralized, open source package manager for C and C++.
  • cpm: CMake Package Manager. Despite its name, its not affiliated with the CMake Project.
  • vcpkg: Microsoft's cross-platform, free and open source C/C++ package manager for acquiring and managing libraries.
  • xrepo: xmake's complementary package manager that uses conan's and vcpkg's repository.
  • Hunter: CMake driven cross-platform package manager for C/C++.


Compilers

Established

Well established compilers used in production by overwhelming majority of C programmers.

  • GCC: The GNU Compiler Collection (Originally known as the GNU C Compiler...)
  • Clang/LLVM: An "LLVM native" C/C++/Objective-C compiler.
  • MSVC: Microsoft's Proprietary C/C++ Compiler. Only available within Visual Studio which is only on Windows.
  • ICC: The Intel C Compiler. Proprietary compiler that uses LLVM as its backend. Caution should be taken if used due to previous behavior by Intel (Maliciously generating slower code for non-Intel processors).
  • AOCC: AMD Optimizing C, C++, and Fortran Compiler. Proprietary fork of LLVM + Clang that adds numerous patches designed to improve performance for AMD's Zen microarchitecture that is within Epyc (server oriented) and Ryzen (desktop oriented) chips.
  • armcc: ARM's C Compiler. Has variants for server and embedded.

Enthusiast

Compilers that are either developed by and for hobbyists or are still being developed.

  • cproc(github mirror): Small, optimizing C compiler using QBE for its backend. Supports C11 as well as portions of C23 and some GNU extensions. Unlike TCC, cproc does not include its own pre-processor or linker. However, it produces significantly more performant executables, reaching roughly ~75-80% the speed of GCC -O2 at only ~80K SLOC (counting QBE). Takes inspiration from several smaller and obscure c compilers like 8cc, c, lacc, and scc.
  • Cuik - A modern C11 compiler intended to be quick hence the name. Complete toolchain built to replace GCC, MSVC, and LLVM. It's built in a modular design, the C11 frontend is one library (libCuik) along with the backend (tb / TildeBackend) which can both be compiled separately. Still being developed under the new-cg branch.
  • TCC: The Tiny C Compiler is notable for its extremely fast compilation speeds. Originated as a relatively small program made by Fabrice Bellard during a code competition. Bellard continued to develop it for a while after the contest but has left the project for other things. It is still being developed by many enthusiasts including some who work on GCC.
  • MIR: Red Hat's upcoming ultra-lightweight MIT-licensed JIT compiler-backend written in C and clocking in at under 15K SLOC. Includes a usable reference C compiler (c2mir) capable of cproc-like performance. Suitable alternative to LLVM, libgccjit, and QBE for building new compilers. Targets Linux AMD64, ARM64, PPC64LE, PPC64BE, RISC-V 64, and s390x as well as macOS AMD64 and ARM64. Unlike QBE, MIR has initial support for 32-bit platforms in addition to 64-bit.
  • scc: The Simple C Compiler.

Obscure

  • pcc - Portable C Compiler. An early C compiler made by a BELL Labs software engineer in 1973.
  • XCC - Standalone C compiler/assembler/linker/libc for x86-64/aarch64/riscv64/wasm
  • Turbo C: A free C++ compiler from Borland. It comes with an IDE and debugger.
  • CompCert: A C99 compiler intended for the compilation of life-critical and mission-critical software and meeting high levels of assurance. Non-free.
  • Movfuscator: A single instruction (MOV) C89 compiler created for lulz by the reverse-engineering god Christopher Domas.

Linkers

  • ld: GNU's implementation of the original ld linker.
  • gold: A faster alternative to ld originally created by Google before being abandoned. Now also developed and distributed by GNU binutils team. ELF files only.
  • lld: LLVM's linker.
  • mold: An upcoming linker to serves as a drop-in replacement to existing Unix linkers.

Miscellaneous

  • cmake-init: A random /g/entooman's Cmake project initializer.

Recommended Build Options

Standards

-std= (valid: c89, c99 c11 c17, c2x) (additional: c90=c89, c18=c17). Any 'c' can be replaced with 'gnu' for GNU extensions, but you can use them anyway and the compiler won't even warn you unless you specify -pedantic or -Wpedantic so don't worry about it too much unless you're looking to maximize compiler portability.

Determine the language standard. See Language Standards Supported by GCC, for details of these standard versions. This option is currently only supported when compiling C or C++. -std=c99 is usually a good choice.

On MSVC use /D_CRT_SECURE_NO_WARNINGS to disable warnings regarding the so-called "secure" functions. These aren't widely supported outside of MSVC, and their benefits are questionable. See N1967 for more information.

-ansi: Common alias for -std=c89.

Warnings

GCC Warnings are listed here. For both GCC and Clang, it is generally recommended to use -Werror -Wall -Wextra -Wpedantic.

-Werror: Make all warnings into errors.


-Wall: Enables a large set of warnings, some of which may be undesirable. Very recommended to use.


-Wextra: This enables some extra warning flags that are not enabled by -Wall. Recommended to use.


-Wpedantic: Issue all the warnings demanded by strict ISO C and ISO C++; reject all programs that use forbidden extensions, and some other programs that do not follow ISO C and ISO C++. For ISO C, follows the version of the ISO C standard specified by any -std option used (Example: -std=c99).


-Wstrict-aliasing=3: Pointer aliasing is when two different pointers can point to the same memory location. Strict aliasing is a set of rules C compilers use to determine when this can happen and when it can't. 3 may be too high for beginners and can spit out some false-positives, 2 is typically a better choice.


-Wwrite-strings: Warns on write to string literals, which have the type of `char []` however, writing to a string literal is Undefined Behavior (UB), so it makes more sense to treat them as `const char []` (even DMR wanted to make string literals const: https://www.lysator.liu.se/c/dmr-on-noalias.html).


-Wvla: Warns if there is a variable length array used in the code. VLAs are either unnecessary because you know the upper bound and are able to do buf[UPPER_BOUND] or are a stack overflow waiting to happen. Some smaller compilers like cproc do not implement VLAs, possibly avoiding use of this option may aid portability.


-Wcast-align=strict: can warn on some newb casting.


-Wstrict-prototypes: Warns on function declarations that lack an explicit set of parameters like f(), which have a specialized purpose in C and only C, where the set arguments are set at the implementation site.


-Wstringop-overflow=4: Warns for calls to string manipulation functions such as memcpy or strcpy that are determined to overflow the destination buffer. At =4 it additionally warns about overflowing any data members, and when the destination is one of several objects it uses the size of the largest of them to decide whether to issue a warning.


-Wno-logical-op-parentheses: C has an order precedence of first && then ||. This is however warned against, and at a glance with this knowledge it is much easier to tell the difference between (a && b || c) and (a && (b || c)) than enforcing that warning like ((a && b) || c) and (a && (b || c)).


-Wshadow: Warns when a block re-declares a variable already declared in a higher block. This is often done intentionally but beginners may wish to be warned on it because the bugs it can cause are particularly subtle and difficult to debug, since the debugger will not tell you what the actual problem is.


-Weverything: Exclusive to clang and only intended for developing clang itself. May require many -Wno-... options to not emit too many false positives, but the perfectionist or anon who simply can't be bothered to run a linter may find it useful.


-fanalyzer: Perform advanced static analysis. Massively increases compile times but can catch nontrivial memory errors and does not impart a runtime performance penalty unlike -fsanitize= (see below).

Optimizing & Release options

GCC optimization options can be seen here.

-O0: Reduce compilation time and make debugging produce the expected results. This is the default.


-O1: Optimize. Optimizing compilation takes somewhat more time, and a lot more memory for a large function. With -O, the compiler tries to reduce code size and execution time, without performing any optimizations that take a great deal of compilation time.


-O2: Optimize even more. GCC performs nearly all supported optimizations that do not involve a space-speed tradeoff. As compared to -O, this option increases both compilation time and the performance of the generated code.


-O3: Enables all optimizations specified by -O2 and some additional flags. Can drastically increase binary size due to loop unrolling, particularly with clang. It is somewhat overfitted to x86-64 processors, and other architectures may actually see worse performance with this option even with an appropriate -march.


-Ofast: Disregard strict standards compliance. Enables all -O3 optimizations. It also enables optimizations that are not valid for all standard-compliant programs. It turns on -ffast-math, -fallow-store-data-races and the Fortran-specific -fstack-arrays, unless -fmax-stack-var-size is specified, and -fno-protect-parens. It turns off -fsemantic-interposition. Do not use this if your code relies on specified IEEE float behavior or if you have multiple threads accessing the same data, even with locks. Even if your code doesn't, extensive testing is required to guarantee you can get away with this flag, and the benefit is small even when you can. Avoid if you are a beginner.


-Os: Optimize for size. Enables all -O2 optimizations except those that often increase code size. It also enables -finline-functions, causes the compiler to tune for code size rather than execution speed, and performs further optimizations designed to reduce code size. Generally not recommended due to its "hyper-focus" on minimizing the size of a program, even at the expense of obvious, highly beneficial optimizations.


-Oz: Optimize strongly for size. The difference is small for gcc, but clang's -Os is not nearly as aggressive as gcc's, so the difference there is larger.


-Og: Optimize debugging experience. Should be the optimization level of choice for the standard edit-compile-debug cycle, offering a reasonable level of optimization while maintaining fast compilation and a good debugging experience. It is a better choice than -O0 for producing debuggable code because some compiler passes that collect debug information are disabled at -O0. Like -O0, -Og completely disables a number of optimization passes so that individual options controlling them have no effect. Otherwise -Og enables all -O1 optimization flags except for those that may interfere with debugging.


-flto=auto: Perform link-time optimization. There is some confusion about LTO because the supported way to do it has changed a lot over the years but in 2023 with gcc 13 or clang 16 just using -flto=auto should make everything just work. Or, you may need SET(CMAKE_AR "gcc-ar") and SET(CMAKE_RANLIB "gcc-ranlib") when using cmake because cmake hates using gcc correctly for some reason. And with clang you may need -fuse-ld=lld because Ubuntu is shit. There is quite a bit of difference between how LTO works between gcc and clang. With clang, -flto=auto is an alias for -flto=full, which treats the entire program as one codegen unit at the cost of parallelism. Clang can only parallelize LTO with -flto=thin, which skips many optimizations. This is distinct from the concept of thin LTO objects in gcc which are just object files with only GIMPLE bytecote and no machine code so they require LTO at link-time to be used. Note that the reverse is never true: executables compiled with LTO will happily link against objects and static libraries that lack it with no problem (except foregone performance). In gcc you do not need to worry about this full/thin tradeoff because whole-program analysis is performed unconditionally. In particular, you DO NOT need -flto=1, -fuse-linker-plugin, -ffat-lto-objects, -fwhole-program, or -flto-partition=one to squeeze the maximum performance out: gcc will prove its LTO partitions do not forego any optimizations. The -flto=N option only controls how many jobs the LTO wrapper can accept at once, it does not parallelize the jobs themselves. The jobs will be parallelized by -flto-partition=balanced (the default) in a way that still catches all optimizations. The LTO plugin is loaded automatically when passing -flto to gcc. -fwhole-program manually guarantees what the plugin has already either proven true or false, so it will either not help or will introduce UB. Don't use it. -ffat-lto-objects allows objects and static library archives to be linked against executables that do not themselves use -flto, and should be left off unless you want LTO to silently break and not tell you. It has nothing to do with fat LTO in Rust. Make sure you use the =auto part or you will bottleneck your Makefiles for no reason because you are only allowing one lto-wrapper to run at once despite that fact that the parallelism has no drawbacks. Or, in the case of clang, you are getting parallelism but with big drawbacks so =auto turns it off. At any rate when using a Makefile the number of threads used for LTO with =auto is capped at -j so you don't need two $(nproc) calls. For more information, see here. TL;DR: Just use -flto=auto! Reading all the wrong StackOverflow answers about this is giving me brain damage!


-march=native: Optimize the code for your processor. This is of limited usefulness with gcc since it barely auto-vectorizes compared to clang, but it will still enable any code paths conditional on architecture support and will take caching and microarchitecture behaviors into consideration. If you're using a specific microarchitecture like znver2 or native, you DO NOT need to also use -mtune.


-s and strip: strip is primarily useful for release builds, it strips unneeded symbols and can be invoked at compile- or link-time with -s or separately after the fact with strip PROGRAM


-pipe: Use pipes instead of temporary files when compiling. Saves your SSD for negligible (probably) compile-time memory cost.


-f1337-epic-option: Some of these are useful if you are minifying a nolibc executable but in general if you are a beginner or are just looking for performance these will just cause you headaches. Stick to the basics: -O3, -flto=auto, -march=native, -pipe, -s.


NOTE: Optimizers aren't magic. Your code will still be slow if it's shit. See this talk for just the tip of the iceberg. Don't use linked lists just because they're easy!

Debug options

Generally -Og -g, use -ggdb instead of -g if you intend to use GNU Debugger. -fsanitize=... has many useful features described in The GCC PDF, you however cannot combine some directives with any debugger. The most common ones are address and undefined.

Tools like Valgrind, Splint may also help you debug and improve your code.

Diagnostic options

Consider -fno-diagnostics-show-caret for GCC or -fno-caret-diagnostics for Clang to reduce the number of lines per actual error in the compiler output.

Other Recommendations

Thread 23: >>94944789

Anonymous >>95011850
should i pass structs as parameters, or only a pointer to the struct.
Anonymous >>95012180
The usual rule of thumb is if you can fit the struct into 2 registers then pass it by value, otherwise by pointer. In reality it's more complicated. There are semantic reasons for wanting to accept by value, e.g. to make the code easier to work with. If the function is static then it's basically always fine to pass it by value because the optimizer can change it to accept a pointer (assuming you don't modify the copy of the struct), similar thing with returning structs by value, the compiler will allocate stack memory and pass in a pointer that will be filled instead of having it copied out. If you compile with LTO then this can happen across translation unit boundaries for non-static functions, but without LTO the compiler has to abide by the target ABI. In this case it's usually better to pass by pointer using the previous rule of thumb, but if you read the ABI spec for your target you will find that it's more complicated than if it can fit in 2 registers, there are a bunch of rules that determine whether a parameter is passed in a register or copied as an argument to the stack. Really the cost for non-optimized function calls is determined by the parameter passing rules defined in the target ABI, the cost memory lookup on the target, and whether the struct is in cache or not.

Thread 0: >>92317404

Anonymous >>92317996
>>92317404 (OP)
How do I into C? I know a few other programming languages, so I'm less interested in syntax and such. But more best practices.
Anonymous >>92340750 (pruned)
>>92317996
My tips:
>Compile with -Wall -Wextra. In debug builds, use sanitizers too.
>For complex cross-platform programs CMake or meson can be helpful, but for simple programs make is often sufficient.
>Don't overuse the preprocessor. Use something else if possible without too much hackery. For example, sometimes you can use an inline function. For int constants, you can use enum instead of #define.
>You can organize a larger program by using prefixes. E.g. all color functions start with color_ and are in color.c/color.h, random generators start with rnd_ and are in rnd.c/rnd.h.
>Prefer reentrant to non-reentrant functions, e.g. strtok_r instead of strtok. Also avoid any string functions which can cause buffer overflow because they don't take a length, e.g. strcat or gets.
Anonymous >>92318458
>>92317996
Avoid malloc'ing & returning the malloc'd memory from your functions. Instead, have them accept a buffer pointer + size to write to. Keep free's as close to their malloc's as possible.

Don't use any string functions other than strnlen. Each string handling function has its own peculiar way to handle the \0 that you have to remember, and they barely save you any time compared to just doing the pointer arithmetic yourself & using memcpy. strcat is particularly notorious for tempting you into writing accidentally quadratic code.

Keep your statements short and simple. Reading & writing to a variable in the same expression is undefined behavior. The order of evaluation of the arguments to a function is also unspecified, so don't write shit like f(a++, b, a+c) expecting a particular evaluation order.

Turn on all possible compiler warnings & use -Werror.

Define as few globals as possible. If you have to, try to keep them static to their translation unit.

Macros are shit, but unavoidable. When defining them, parenthesize all your macro args and avoid repeating them, lest you'll accidentally mutate state twice when invoking them.

Macros that expand to expressions should have their whole definitions wrapped in parentheses.
Macros that expand to statements should have their whole definitions wrapped in a do{...}while(0) statement with no trailing semicolon.

C programmers love linked lists. Expect to run into lots of them while reading C code. If you wanna know why, try implementing a growable array in C.
Xolatile >>92335411
> Avoid malloc'ing & returning the malloc'd memory...
Actually, using 'calloc' is safer referring to Splint (very strict C99 linter) because it defines allocated memory segment, fills it with 0s, and validates a type if used correctly...
> Turn on all possible compiler warnings...
I completely agree, and I use different compilers with maximum warnings enabled with -Werror only in "finishing stage", along with Valgrind (always) and Splint (sometimes).
> Define as few globals as possible.
It's best to have no global variables, pass variables to functions like a proper programmer, state is the root of a lot of hard to track bugs. (:
> Macros are shit, but unavoidable.
I usually have 0 macros in my programs, I define constants inside enumerations. I don't use ifdef, ifndef, define, endif, etc. because I don't write cross-platform programs...
Due to autism, sometimes I don't even use #include, but instead write "extern ..." at the start of my source code files, or pass -include flag to compiler...
--
I missed this when it was posted Anon, but I agree with most of your points, except macros mostly, they should be avoided at all cost, especially function-like macros. (:
I usually implement my own "printf" without variadics, passing in a format as string, and array of union of basic types.

C Misconceptions

C is too small of a language to be useful!

While C is a relatively small language, it provides enough facilities to create anything you can imagine. It's no secret that most interpreted languages like Perl, Python, Lua, and countless Lisps/Schemes/Forths are implemented in C. Anything you can implement in the aforementioned languages, can also be implemented in C. This could be said about many small languages which aren't usable at all, but C provides enough tools of abstraction to be useful in projects of any scale, from /usr/bin/true to /boot/vmlinuz.

On the other hand, C's simplicity makes it much easier to learn the whole language. Anyone with previous programming experience can learn the entirety of C in just a few weeks. After learning the language itself, one spends the rest of their C programming career figuring out the best way to apply it. This is more productive, as you're gaining actual CS knowledge and not focusing on superficial things like a particular language's syntax/implementation details.

C has no package manager!

C has many, many package managers, one for every GNU/Linux Distribution. Language-specific package managers tend to be a bad idea anyway

C's lack of memory safety leads to buggy programs!

Good coding habits will prevent many such bugs. There are also tools like ASan and UBSan which help find memory bugs during testing. Large codebases may consider using talloc, which provides safe wrappers around the system malloc() and will catch 97% of memory errors at compile- or run-time.