3 ms·
I'm a security student. My main experience has been python and java....but I have started to learn c to better learn how low level stuff works without so much
by tonetegeatinst 2y ago
I'm a security student. My main experience has been python and java....but I have started to learn c to better learn how low level stuff works without so much abstraction.
My understanding is that C is a great language, but I also get that its not for everyone. Its really powerful, and yet you can easily make mistakes.
For me, I'm just learning how to use C, I'm not trying to understand the compiler or make files yet. From what I get, the compiler is how you can achieve even better performance, but you need to understand how it is doing its black magic....otherwise you just might make your code slower or more inefficient.
- vlovich123 2y agoFirst order optimization is always overall program architecture, then hotspots, then fixing architectural issues in the code (e.g. getting rid of misspeculated branches, reducing instructions etc), and then optimizing the code the compiler is generating. And at no point does it require to know the internals of the optimization passes as to how it generates the code. As for the compiler’s role in C, it’s equivalent to javac - it’s taking your source and creating machine code, except the machine code isn’t an abstract bytecode but the exact machine instructions intended to run on the CPU. The issues with C and C++ are around memory safety. Practice has repeatedly shown that the defect rate with these languages is high enough that it results in lots of easily exploitable vulnerabilities. That’s a bit more serious than a personal preference. That’s why there’s pushes to shift the professional industry itself to stop using C and C++ in favor of Rust or even Go.
- torusle 2y agoNah, it is not that bad. Sure you can mess up your performance by picking bad compiler options, but most of the time you are fine with just default optimizations enabled and let it do it's thing. No need to understand the black magic behind it. This is only really necessary if you want to squeeze the last bit of performance out of a piece of code. And honestly, how often dies this occur in day to day coding unless you write a video or audio codec?
- vlovich123 2y agoThe main flags to look at: * mtune/march - specifying a value of native optimizes for the current machine, x86-64-v1/v2/v3/v4 for generations or you can specify a specific CPU (ARM has different naming conventions). Recommendation: use the generation if distributing binaries, native if building and running locally unless you can get much much more specific * -O2 / -O3 - turn on most optimizations for speed. Alternatively Os/Oz for smaller binaries (sometimes faster, particularly on ARM) * -flto=thin - get most of the benefits of LTO with minimal compile time overhead * pgo - if you have a representative workload you can use this to replace compiler heuristics with real world measurements. AutoFDO is the next evolution of this to make it easier to connect data from production environments to compile time. * math: -fno-math-errno and -fno-trapping-math are “safe” subsets of ffast-math (i.e. don’t alter the numerical accuracy). -fno-signed-zeros can also probably be considered if valuable.
- vbezhenar 2y agoAlso I learned recently that there's `-Og` which enables optimizations suitable for debug build.
- vlovich123 2y agoIn practice I’ve had limited success with that flag. It still seems to enable optimizations that make debugging difficult.
- senkora 2y agoAgreed. I like to compile most translation units with -O3 and then only compile the translation units that I want to debug with -O0. That way I can often end up with a binary that's reasonably fast but still debuggable for the parts that I care about.
- vlovich123 2y agoYup that’s what I’ve resorted to (in Rust I do it at the crate level instead of translation unit). The only downside is forgetting about it and then wondering why stepping through is failing to work properly.