hello friends! new(ish)!
C Help and Discussion: Difference between revisions
>Emil (Added template and formatting on the introductory paragraph.) |
>Emil m (Introductory formatted.) |
||
Line 6: | Line 6: | ||
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. | ||
Show and talk about what your currently working on, or things you've worked on in the past. | Show and talk about what your currently working on, or things you've worked on in the past. | ||
Revision as of 22:50, 11 April 2023
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.
Tools
Building and Build systems
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.
Video guide by David A. Wheeler · Basic Template
Makefile
"A Makefile a day keeps the doctor away." - me
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.
CMake
CMake is a multi-platform build system that is a modern alternative to Autotools. It's generally considered to have bad syntax.
Meson
CMake with better syntax.
Debugging tools
Valgrind
Memory leak detector, cache checker, and some other tools.
Splint
Linter for your leg.
gdb
> Take your anger out on the debugger on basket weaving internet forums because you can't debug your vaporware
lldb
Stub.
Recommended Build Options
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).
-std=
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.
-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 can 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))
.
Optimizing & Release options
GCC optimization options can be seen here.
-O2 -DNDEBUG
Provides good optimizations for most use-cases.
-O0
Reduce compilation time and make debugging produce the expected results. This is the default.
-O
or -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
Optimize yet more. -O3
turns on all optimizations specified by -O2
and some additional flags.
-Ofast
Disregard strict standards compliance. -Ofast
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
.
-Os
Optimize for size. -Os
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.
-Og
Optimize debugging experience. -Og
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=N
or -fwhole-program
N
represents the number of processes you use to handle LTO, higher numbers means faster, run nproc
to see how many threads you can at most use.
LTO may greatly slow building, and is not to be used constantly during development cycles.
-fwhole-program
provides optimization by the knowledge of 'this is the whole program', and may be put against Main and is most commonly used against a single compilation unit.
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.
Debug options
Generally -Og -g -fsanitize=address,undefined
, use -ggdb
instead of -g
if you intend to use GNU Debugger.
-fsanitize=...
has many other useful features described in The GCC PDF.
Tools like Valgrind, Splint will 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.
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.
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.
Useful Links
Getting started
Challenge
Books
Standards
Articles
- Some Were Meant For C
- Untangling Lifetimes: The Arena Allocator
- Memory Allocation Strategies
- Modern C for C++ Peeps
Notable Projects Summited
Advice
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
From >>92426366 In >>92422644, slightly edited:
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.
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.
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 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.
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.
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.
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.
Template
Lets have a C thread. Post what your working on! Show what your interested in now.
WIKI : https://wiki.installgentoo.com/wiki/C_Help_and_Discussion IRC : irc://irc.rizon.net:+6697/%2Fg%2Fchad
Last thread : >>OLD